package services

import (
	"bookhoard/internal/database"
	"bookhoard/internal/utils"
	"context"

	"github.com/jackc/pgx/v5/pgtype"
)

type SeriesInfo struct {
	Name          string
	BookCount     int64
	TotalInSeries int
	CoverPaths    []string
	LastEntryAt   string
}

type SeriesService struct {
	db *database.Queries
}

func NewSeriesService(db *database.Queries) *SeriesService {
	return &SeriesService{db: db}
}

func (s *SeriesService) GetSeriesPage(ctx context.Context, libraryID pgtype.UUID, limit, offset int) ([]SeriesInfo, int, error) {
	totalCount, err := s.db.GetDistinctSeriesCount(ctx, libraryID)
	if err != nil {
		return nil, 0, err
	}

	rows, err := s.db.GetDistinctSeries(ctx, database.GetDistinctSeriesParams{
		LibraryID: libraryID,
		Limit:     pgtype.Int4{Int32: int32(limit), Valid: true},
		Offset:    pgtype.Int4{Int32: int32(offset), Valid: true},
	})
	if err != nil {
		return nil, 0, err
	}

	var series []SeriesInfo
	for _, row := range rows {
		seriesName := row.Series.String
		coverPaths, _ := s.GetSeriesCovers(ctx, libraryID, seriesName, 7)

		totalInSeries := 0
		if row.TotalInSeries != nil {
			if v, ok := row.TotalInSeries.(int32); ok {
				totalInSeries = int(v)
			} else if v, ok := row.TotalInSeries.(int64); ok {
				totalInSeries = int(v)
			}
		}

		lastEntry := ""
		if row.LastEntryAt != nil {
			switch v := row.LastEntryAt.(type) {
			case pgtype.Timestamptz:
				if v.Valid {
					lastEntry = v.Time.String()
				}
			case string:
				lastEntry = v
			}
		}

		if totalInSeries == 0 || totalInSeries < int(row.BookCount) {
			totalInSeries = int(row.BookCount)
		}

		series = append(series, SeriesInfo{
			Name:          seriesName,
			BookCount:     row.BookCount,
			TotalInSeries: totalInSeries,
			CoverPaths:    coverPaths,
			LastEntryAt:   lastEntry,
		})
	}

	if series == nil {
		series = []SeriesInfo{}
	}

	return series, int(totalCount), nil
}

func (s *SeriesService) GetSeriesCovers(ctx context.Context, libraryID pgtype.UUID, seriesName string, limit int) ([]string, error) {
	covers, err := s.db.GetSeriesCovers(ctx, database.GetSeriesCoversParams{
		LibraryID: libraryID,
		Series:    pgtype.Text{String: seriesName, Valid: true},
		Limit:     pgtype.Int4{Int32: int32(limit), Valid: true},
	})
	if err != nil {
		return nil, err
	}

	paths := make([]string, 0, len(covers))
	for _, c := range covers {
		resolved := utils.ResolveMediaURL(c.LibraryID, c.CoverImagePath)
		if resolved != "" {
			paths = append(paths, resolved)
		}
	}

	return paths, nil
}

func (s *SeriesService) GetSeriesBooks(ctx context.Context, seriesName string) ([]database.MediaItems, error) {
	return s.db.GetSeriesBooks(ctx, pgtype.Text{String: seriesName, Valid: true})
}

func continueSeriesRowToMediaItems(row database.GetContinueSeriesItemsRow) database.MediaItems {
	return database.MediaItems{
		ID: row.ID, LibraryID: row.LibraryID, Title: row.Title, Author: row.Author,
		Isbn: row.Isbn, Description: row.Description, FilePath: row.FilePath,
		FileSize: row.FileSize, MimeType: row.MimeType, CoverImagePath: row.CoverImagePath,
		Series: row.Series, SeriesNumber: row.SeriesNumber, Tags: row.Tags, Asin: row.Asin,
		DatePublished: row.DatePublished, Publisher: row.Publisher, Contributors: row.Contributors,
		Language: row.Language, Edition: row.Edition, PageCount: row.PageCount,
		Genre: row.Genre, CopyrightYear: row.CopyrightYear, GoodreadsID: row.GoodreadsID,
		OpenlibraryID: row.OpenlibraryID, GoogleBooksID: row.GoogleBooksID,
		AddedByAdminID: row.AddedByAdminID, CreatedAt: row.CreatedAt, UpdatedAt: row.UpdatedAt,
		FormatGroup: row.FormatGroup, FormatMimetype: row.FormatMimetype,
		IsReflowable: row.IsReflowable, HasFixedLayout: row.HasFixedLayout,
		TotalCharacters: row.TotalCharacters, ChapterCount: row.ChapterCount,
		EntitlementID: row.EntitlementID, RevisionNumber: row.RevisionNumber,
		KoboContentID: row.KoboContentID, KoboMetadata: row.KoboMetadata,
		MangaType: row.MangaType, ReadingDirection: row.ReadingDirection,
		SeriesCount: row.SeriesCount, Volume: row.Volume, Imprint: row.Imprint,
		AgeRating: row.AgeRating, WebUrl: row.WebUrl, StoryArc: row.StoryArc,
		IsBlackAndWhite: row.IsBlackAndWhite, MetadataNotes: row.MetadataNotes,
		CommunityRating: row.CommunityRating, AlternateInfo: row.AlternateInfo,
		ScanInformation: row.ScanInformation, Summary: row.Summary,
		ChapterMetadata: row.ChapterMetadata, LibraryTypeName: row.LibraryTypeName,
		TagsSearch: row.TagsSearch, ContributorsSearch: row.ContributorsSearch,
		FileSha256: row.FileSha256, OpfIdentifier: row.OpfIdentifier,
		OpfUuid: row.OpfUuid, HashConfidence: row.HashConfidence,
	}
}
