package router

import (
	"bookhoard/internal/database"
	"bookhoard/internal/handlers"
	"bookhoard/internal/services"
	"bookhoard/internal/sync"
	"bookhoard/internal/utils"
	"bookhoard/templates"
	"bytes"
	"errors"
	"net/http"

	"github.com/google/uuid"
	"github.com/jackc/pgx/v5"
	"github.com/jackc/pgx/v5/pgtype"
	"github.com/labstack/echo/v5"
)

func registerReaderRoutes(cfg *Config) {
	e := cfg.Echo

	// Create reader service and handler
	readerService := services.NewReaderService(cfg.Queries, cfg.Worker)
	cfg.ReaderHandler = handlers.NewReaderHandler(
		cfg.Queries,
		services.NewLibraryService(cfg.Queries),
		readerService,
		cfg.Worker,
	)

	jwtMiddleware := createJWTMiddleware(cfg)

	// Reader page routes (SSR + API)
	reader := e.Group("/readers", jwtMiddleware)

	// Reader page (SSR)
	reader.GET("/:mediaItemId", func(c *echo.Context) error {
		// Get user
		user, err := getTemplateUserWithTheme(c, cfg)
		if err != nil {
			return renderErrorPage(c, "Error loading user", "user_load_error")
		}
		// Parse mediaItemID
		mediaItemID := c.Param("mediaItemId")
		parsedUUID, err := uuid.Parse(mediaItemID)
		if err != nil {
			return renderErrorPage(c, "Invalid media item ID", "invalid_id")
		}
		// Fetch media item (directly, no handler)
		mediaItem, err := cfg.Queries.GetMediaItem(c.Request().Context(), pgtype.UUID{Bytes: parsedUUID, Valid: true})
		if err != nil {
			return renderErrorPage(c, "Media item not found", "not_found")
		}
		// Check library access (using pattern from opds.go)
		userUUID, _ := uuid.Parse(user.ID)
		libraries, err := cfg.Queries.GetUserVisibleLibraries(c.Request().Context(), uuidToPGType(userUUID))
		if err != nil {
			return renderErrorPage(c, "Failed to check access", "access_error")
		}

		visible := false
		for _, lib := range libraries {
			if lib.ID == mediaItem.LibraryID {
				visible = true
				break
			}
		}
		if !visible {
			return renderErrorPage(c, "Access denied", "access_denied")
		}
		// Get reading progress
		var progress database.ReadingProgress
		progress, err = cfg.Queries.GetReadingProgress(c.Request().Context(), database.GetReadingProgressParams{
			MediaItemID: pgtype.UUID{Bytes: parsedUUID, Valid: true},
			UserID:      uuidToPGType(userUUID),
		})
		if err != nil && !errors.Is(err, pgx.ErrNoRows) {
			progress = database.ReadingProgress{}
		}
		// Get bookmarks
		bookmarks, _ := cfg.Queries.GetMediaBookmarks(c.Request().Context(), database.GetMediaBookmarksParams{
			MediaItemID: pgtype.UUID{Bytes: parsedUUID, Valid: true},
			UserID:      uuidToPGType(userUUID),
		})
		// Convert to template types
		mediaUUID, _ := uuid.FromBytes(mediaItem.ID.Bytes[0:16])
		libUUID, _ := uuid.FromBytes(mediaItem.LibraryID.Bytes[0:16])
		metadata := templates.ReaderMetadata{
			MediaItemID:      mediaUUID.String(),
			Title:            mediaItem.Title,
			Author:           textToString(mediaItem.Author),
			CoverImagePath:   textToString(mediaItem.CoverImagePath),
			LibraryType:      mediaItem.FormatGroup,
			MimeType:         textToString(mediaItem.MimeType),
			FilePath:         mediaItem.FilePath,
			TotalPages:       int(mediaItem.PageCount.Int32),
			ChapterCount:     int(mediaItem.ChapterCount.Int32),
			FormatGroup:      mediaItem.FormatGroup,
			MangaType:        textToString(mediaItem.MangaType),
			ReadingDirection: textToString(mediaItem.ReadingDirection),
			LibraryID:        libUUID.String(),
			FileURL:          utils.ResolveMediaURL(mediaItem.LibraryID, pgtype.Text{String: mediaItem.FilePath, Valid: true}),
			TotalCharacters:  mediaItem.TotalCharacters.Int64,
			EstimatedPages:   sync.EstimatedPages(mediaItem.TotalCharacters.Int64),
		}
		// Progress conversion (inline)
		progressUUID, _ := uuid.FromBytes(progress.ID.Bytes[0:16])
		progressMediaUUID, _ := uuid.FromBytes(progress.MediaItemID.Bytes[0:16])
		progressUserUUID, _ := uuid.FromBytes(progress.UserID.Bytes[0:16])
		templateProgress := templates.ReadingProgress{
			ID:              progressUUID.String(),
			MediaItemID:     progressMediaUUID.String(),
			UserID:          progressUserUUID.String(),
			CurrentPage:     int(progress.CurrentPage.Int32),
			TotalPages:      int(progress.TotalPages.Int32),
			Percentage:      progress.Percentage.Float64 * 100,
			EpubCfi:         textToString(progress.Epubcfi),
			LastReadAt:      progress.LastReadAt.Time,
			Chapter:         int(progress.Chapter.Int32),
			ChapterProgress: progress.ChapterProgress.Float64 * 100,
			FormatGroup:     mediaItem.FormatGroup,
		}
		// Bookmarks conversion (inline, with loop)
		templateBookmarks := make([]templates.Bookmark, len(bookmarks))
		for i, b := range bookmarks {
			bookmarkUUID, _ := uuid.FromBytes(b.ID.Bytes[0:16])
			bookmarkMediaUUID, _ := uuid.FromBytes(b.MediaItemID.Bytes[0:16])
			bookmarkUserUUID, _ := uuid.FromBytes(b.UserID.Bytes[0:16])

			var pageNumber *int
			if b.PageNumber.Valid {
				val := int(b.PageNumber.Int32)
				pageNumber = &val
			}

			var chapterNumber *int
			if b.ChapterNumber.Valid {
				val := int(b.ChapterNumber.Int32)
				chapterNumber = &val
			}

			templateBookmarks[i] = templates.Bookmark{
				ID:            bookmarkUUID.String(),
				MediaItemID:   bookmarkMediaUUID.String(),
				UserID:        bookmarkUserUUID.String(),
				PageNumber:    pageNumber,
				ChapterNumber: chapterNumber,
				CfiPosition:   textToString(b.CfiPosition),
				Title:         b.Title,
				Position:      textToString(b.Position),
				Notes:         textToString(b.Notes),
				CreatedAt:     b.CreatedAt.Time,
			}
		}
		// 8. Render template
		var buf bytes.Buffer
		err = templates.Reader(user, metadata, templateProgress, templateBookmarks).Render(c.Request().Context(), &buf)
		if err != nil {
			return renderErrorPage(c, "Error rendering reader", "render_error")
		}
		return c.HTML(http.StatusOK, buf.String())
	})

	// Content serving (lazy-loaded pages)
	reader.GET("/:mediaItemId/pages/:pageNumber", cfg.ReaderHandler.GetPage)

	// Chapter metadata
	reader.GET("/:mediaItemId/chapters", cfg.ReaderHandler.GetChapters)

	// Panel data (comics/manga)
	reader.GET("/:mediaItemId/panels/:pageNumber", cfg.ReaderHandler.GetPanels)
	reader.PUT("/:mediaItemId/panels/:pageNumber", cfg.ReaderHandler.UpdatePanels)

	// PDF outline/TOC
	reader.GET("/:mediaItemId/outline", cfg.ReaderHandler.GetPDFOutline)

	// PDF thumbnails (for mini-map)
	reader.GET("/:mediaItemId/thumbnails/:pageNumber", cfg.ReaderHandler.GetPDFThumbnail)

	// Reading speed
	reader.GET("/:mediaItemId/reading-speed", cfg.ReaderHandler.GetReadingSpeed)
	reader.POST("/:mediaItemId/reading-speed", cfg.ReaderHandler.UpdateReadingSpeed)

	// Dictionary lookup
	reader.GET("/dictionary/:word", cfg.ReaderHandler.LookupWord)

	// Reader settings
	reader.GET("/settings", cfg.ReaderHandler.GetSettings)
	reader.PUT("/settings", cfg.ReaderHandler.UpdateSettings)
}
