package handlers

import (
	"bookhoard/internal/database"
	"net/http"
	"time"

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

type SyncHandler struct {
	db *database.Queries
}

func NewSyncHandler(db *database.Queries) *SyncHandler {
	return &SyncHandler{db: db}
}

type UnlinkedBookResponse struct {
	Unlinked []UnlinkedBookItem `json:"unlinked"`
	Total    int                `json:"total"`
}

type UnlinkedBookItem struct {
	UnlinkedBookID  string    `json:"unlinked_book_id"`
	DeviceID        string    `json:"device_id"`
	DeviceName      string    `json:"device_name"`
	DeviceType      string    `json:"device_type"`
	ContentId       string    `json:"content_id"`
	FilePath        string    `json:"file_path,omitempty"`
	Title           string    `json:"title,omitempty"`
	Author          string    `json:"author,omitempty"`
	ConfidenceScore float64   `json:"confidence_score"`
	LastSeenAt      time.Time `json:"last_seen_at"`
	CreatedAt       time.Time `json:"created_at"`
}

type LinkBookRequest struct {
	UnlinkedBookID  string  `json:"unlinked_book_id"`
	MediaItemID     string  `json:"media_item_id"`
	ConfidenceScore float64 `json:"confidence_score"`
}

type LinkBookResponse struct {
	Status         string `json:"status"`
	UnlinkedBookID string `json:"unlinked_book_id"`
	MediaItemID    string `json:"media_item_id"`
	Message        string `json:"message"`
}

// GetUnlinkedBooks returns all unlinked books for a user's devices
// GET /api/sync/unlinked-books
func (h *SyncHandler) GetUnlinkedBooks(c *echo.Context) error {
	// Get user from context (assuming auth middleware sets this)
	user := c.Get("user")
	if user == nil {
		return c.JSON(http.StatusUnauthorized, map[string]string{
			"error": "unauthorized",
		})
	}

	userID := user.(database.Users).ID

	// Get all devices for this user
	devices, err := h.db.ListDevicesByUser(c.Request().Context(), pgtype.UUID{Bytes: userID.Bytes, Valid: true})
	if err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]string{
			"error": "failed to fetch devices",
		})
	}

	var allUnlinkedBooks []UnlinkedBookItem

	// For each device, get unlinked books
	for _, device := range devices {
		unlinkedBooks, err := h.db.GetUnlinkedBooksByDevice(c.Request().Context(), pgtype.UUID{Bytes: device.ID.Bytes, Valid: true})
		if err != nil {
			continue
		}

		for _, ub := range unlinkedBooks {
			allUnlinkedBooks = append(allUnlinkedBooks, UnlinkedBookItem{
				UnlinkedBookID:  uuid.UUID(ub.ID.Bytes).String(),
				DeviceID:        uuid.UUID(ub.DeviceID.Bytes).String(),
				DeviceName:      ub.DeviceName,
				DeviceType:      ub.DeviceType,
				ContentId:       ub.ContentID,
				FilePath:        ub.FilePath.String,
				Title:           ub.Title.String,
				Author:          ub.Author.String,
				ConfidenceScore: ub.ConfidenceScore.Float64,
				LastSeenAt:      ub.LastSeenAt.Time,
				CreatedAt:       ub.CreatedAt.Time,
			})
		}
	}

	return c.JSON(http.StatusOK, UnlinkedBookResponse{
		Unlinked: allUnlinkedBooks,
		Total:    len(allUnlinkedBooks),
	})
}

// LinkBook manually links an unlinked book to a media item
// POST /api/sync/link-book
func (h *SyncHandler) LinkBook(c *echo.Context) error {
	var req LinkBookRequest
	if err := c.Bind(&req); err != nil {
		return c.JSON(http.StatusBadRequest, map[string]string{
			"error": "invalid request format",
		})
	}

	// Parse UUIDs
	unlinkedBookID, err := uuid.Parse(req.UnlinkedBookID)
	if err != nil {
		return c.JSON(http.StatusBadRequest, map[string]string{
			"error": "invalid unlinked_book_id",
		})
	}

	mediaItemID, err := uuid.Parse(req.MediaItemID)
	if err != nil {
		return c.JSON(http.StatusBadRequest, map[string]string{
			"error": "invalid media_item_id",
		})
	}

	// Get the unlinked books to find the one we're looking for
	// We need to use GetAllUnlinkedBooks or create a new query
	// For now, let's link directly using LinkUnlinkedBook
	_, err = h.db.LinkUnlinkedBook(c.Request().Context(), database.LinkUnlinkedBookParams{
		ID:              pgtype.UUID{Bytes: unlinkedBookID, Valid: true},
		MediaItemID:     pgtype.UUID{Bytes: mediaItemID, Valid: true},
		ConfidenceScore: pgtype.Float8{Float64: req.ConfidenceScore, Valid: true},
	})
	if err != nil {
		return c.JSON(http.StatusInternalServerError, map[string]string{
			"error": "failed to link book",
		})
	}

	// Note: We can't create a device catalog entry without knowing the device_id and content_id
	// In a real implementation, we'd first fetch the unlinked book, then create the catalog entry

	return c.JSON(http.StatusOK, LinkBookResponse{
		Status:         "linked",
		UnlinkedBookID: req.UnlinkedBookID,
		MediaItemID:    req.MediaItemID,
		Message:        "Book successfully linked",
	})
}
