package cbz

import (
	"archive/zip"
	"bufio"
	"bytes"
	"context"
	"fmt"
	"io"
	"io/fs"
	"path/filepath"
	"strings"

	"github.com/araddon/dateparse"
	"github.com/belphemur/CBZOptimizer/v2/internal/manga"
	"github.com/belphemur/CBZOptimizer/v2/internal/utils/errs"
	"github.com/mholt/archives"
	"github.com/rs/zerolog/log"
)

func LoadChapter(filePath string) (*manga.Chapter, error) {
	log.Debug().Str("file_path", filePath).Msg("Starting chapter loading")

	ctx := context.Background()

	chapter := &manga.Chapter{
		FilePath: filePath,
	}

	// First, try to read the comment using zip.OpenReader for CBZ files
	if strings.ToLower(filepath.Ext(filePath)) == ".cbz" {
		log.Debug().Str("file_path", filePath).Msg("Checking CBZ comment for conversion status")
		r, err := zip.OpenReader(filePath)
		if err == nil {
			defer errs.Capture(&err, r.Close, "failed to close zip reader for comment")

			// Check for comment
			if r.Comment != "" {
				log.Debug().Str("file_path", filePath).Str("comment", r.Comment).Msg("Found CBZ comment")
				scanner := bufio.NewScanner(strings.NewReader(r.Comment))
				if scanner.Scan() {
					convertedTime := scanner.Text()
					log.Debug().Str("file_path", filePath).Str("converted_time", convertedTime).Msg("Parsing conversion timestamp")
					chapter.ConvertedTime, err = dateparse.ParseAny(convertedTime)
					if err == nil {
						chapter.IsConverted = true
						log.Debug().Str("file_path", filePath).Time("converted_time", chapter.ConvertedTime).Msg("Chapter marked as previously converted")
					} else {
						log.Debug().Str("file_path", filePath).Err(err).Msg("Failed to parse conversion timestamp")
					}
				}
			} else {
				log.Debug().Str("file_path", filePath).Msg("No CBZ comment found")
			}
		} else {
			log.Debug().Str("file_path", filePath).Err(err).Msg("Failed to open CBZ file for comment reading")
		}
		// Continue even if comment reading fails
	}

	// Open the archive using archives library for file operations
	log.Debug().Str("file_path", filePath).Msg("Opening archive file system")
	fsys, err := archives.FileSystem(ctx, filePath, nil)
	if err != nil {
		log.Error().Str("file_path", filePath).Err(err).Msg("Failed to open archive file system")
		return nil, fmt.Errorf("failed to open archive file: %w", err)
	}

	// Walk through all files in the filesystem
	log.Debug().Str("file_path", filePath).Msg("Starting filesystem walk")
	err = fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
		if err != nil {
			return err
		}

		if d.IsDir() {
			return nil
		}

		return func() error {
			// Open the file
			file, err := fsys.Open(path)
			if err != nil {
				return fmt.Errorf("failed to open file %s: %w", path, err)
			}
			defer errs.Capture(&err, file.Close, fmt.Sprintf("failed to close file %s", path))

			// Determine the file extension
			ext := strings.ToLower(filepath.Ext(path))
			fileName := strings.ToLower(filepath.Base(path))

			if ext == ".xml" && fileName == "comicinfo.xml" {
				log.Debug().Str("file_path", filePath).Str("archive_file", path).Msg("Found ComicInfo.xml")
				// Read the ComicInfo.xml file content
				xmlContent, err := io.ReadAll(file)
				if err != nil {
					log.Error().Str("file_path", filePath).Str("archive_file", path).Err(err).Msg("Failed to read ComicInfo.xml")
					return fmt.Errorf("failed to read ComicInfo.xml content: %w", err)
				}
				chapter.ComicInfoXml = string(xmlContent)
				log.Debug().Str("file_path", filePath).Int("xml_size", len(xmlContent)).Msg("ComicInfo.xml loaded")
			} else if !chapter.IsConverted && ext == ".txt" && fileName == "converted.txt" {
				log.Debug().Str("file_path", filePath).Str("archive_file", path).Msg("Found converted.txt")
				textContent, err := io.ReadAll(file)
				if err != nil {
					log.Error().Str("file_path", filePath).Str("archive_file", path).Err(err).Msg("Failed to read converted.txt")
					return fmt.Errorf("failed to read converted.txt content: %w", err)
				}
				scanner := bufio.NewScanner(bytes.NewReader(textContent))
				if scanner.Scan() {
					convertedTime := scanner.Text()
					log.Debug().Str("file_path", filePath).Str("converted_time", convertedTime).Msg("Parsing converted.txt timestamp")
					chapter.ConvertedTime, err = dateparse.ParseAny(convertedTime)
					if err != nil {
						log.Error().Str("file_path", filePath).Err(err).Msg("Failed to parse converted time from converted.txt")
						return fmt.Errorf("failed to parse converted time: %w", err)
					}
					chapter.IsConverted = true
					log.Debug().Str("file_path", filePath).Time("converted_time", chapter.ConvertedTime).Msg("Chapter marked as converted from converted.txt")
				}
			} else {
				// Read the file contents for page
				log.Debug().Str("file_path", filePath).Str("archive_file", path).Str("extension", ext).Msg("Processing page file")
				buf := new(bytes.Buffer)
				bytesCopied, err := io.Copy(buf, file)
				if err != nil {
					log.Error().Str("file_path", filePath).Str("archive_file", path).Err(err).Msg("Failed to read page file contents")
					return fmt.Errorf("failed to read file contents: %w", err)
				}

				// Create a new Page object
				page := &manga.Page{
					Index:      uint16(len(chapter.Pages)), // Simple index based on order
					Extension:  ext,
					Size:       uint64(buf.Len()),
					Contents:   buf,
					IsSplitted: false,
				}

				// Add the page to the chapter
				chapter.Pages = append(chapter.Pages, page)
				log.Debug().
					Str("file_path", filePath).
					Str("archive_file", path).
					Uint16("page_index", page.Index).
					Int64("bytes_read", bytesCopied).
					Msg("Page loaded successfully")
			}
			return nil
		}()
	})

	if err != nil {
		log.Error().Str("file_path", filePath).Err(err).Msg("Failed during filesystem walk")
		return nil, err
	}

	log.Debug().
		Str("file_path", filePath).
		Int("pages_loaded", len(chapter.Pages)).
		Bool("is_converted", chapter.IsConverted).
		Bool("has_comic_info", chapter.ComicInfoXml != "").
		Msg("Chapter loading completed successfully")

	return chapter, nil
}
