package handlers

import (
	"context"
	"net/http"
	"strconv"
	"time"

	"github.com/flatrender/render-svc/internal/db"
	"github.com/flatrender/render-svc/internal/middleware"
	"github.com/flatrender/render-svc/internal/models"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"github.com/minio/minio-go/v7"
)

type ExportHandler struct {
	store  *db.Store
	minio  *minio.Client
	bucket string
}

func NewExportHandler(store *db.Store, mc *minio.Client, bucket string) *ExportHandler {
	return &ExportHandler{store: store, minio: mc, bucket: bucket}
}

// GET /v1/exports
func (h *ExportHandler) List(c *gin.Context) {
	userID := middleware.GetUserID(c)
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	if page < 1 {
		page = 1
	}
	exports, total, err := h.store.ListExports(c.Request.Context(), userID, page, 20)
	if err != nil {
		c.JSON(http.StatusInternalServerError, models.APIError{Code: "internal_error", Message: err.Error()})
		return
	}
	if exports == nil {
		exports = []*models.Export{}
	}
	c.JSON(http.StatusOK, models.PagedResponse[*models.Export]{
		Data: exports,
		Meta: models.PaginationMeta{
			Page:     page,
			PageSize: 20,
			Total:    total,
			HasMore:  int64(page*20) < total,
		},
	})
}

// GET /v1/exports/:export_id
func (h *ExportHandler) Get(c *gin.Context) {
	userID := middleware.GetUserID(c)
	exportID, err := uuid.Parse(c.Param("export_id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, models.APIError{Code: "bad_request", Message: "invalid export_id"})
		return
	}
	exp, err := h.store.GetExportByID(c.Request.Context(), exportID, userID)
	if err != nil {
		c.JSON(http.StatusNotFound, models.APIError{Code: "not_found", Message: err.Error()})
		return
	}
	files, _ := h.store.ListExportFiles(c.Request.Context(), exportID)
	if files == nil {
		files = []*models.ExportFile{}
	}
	c.JSON(http.StatusOK, gin.H{
		"id":              exp.ID,
		"saved_project_id": exp.SavedProjectID,
		"path":            exp.Path,
		"image":           exp.Image,
		"size_bytes":      exp.SizeBytes,
		"duration_sec":    exp.DurationSec,
		"width":           exp.Width,
		"height":          exp.Height,
		"file_extension":  exp.FileExtension,
		"file_type":       exp.FileType,
		"render_quality":  exp.RenderQuality,
		"create_type":     exp.CreateType,
		"produce_date":    exp.ProduceDate,
		"auto_delete_date": exp.AutoDeleteDate,
		"files":           files,
	})
}

// DELETE /v1/exports/:export_id
func (h *ExportHandler) Delete(c *gin.Context) {
	userID := middleware.GetUserID(c)
	exportID, err := uuid.Parse(c.Param("export_id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, models.APIError{Code: "bad_request", Message: "invalid export_id"})
		return
	}
	if err := h.store.SoftDeleteExport(c.Request.Context(), exportID, userID); err != nil {
		c.JSON(http.StatusNotFound, models.APIError{Code: "not_found", Message: err.Error()})
		return
	}
	c.Status(http.StatusNoContent)
}

// POST /v1/exports/:export_id/extend
func (h *ExportHandler) Extend(c *gin.Context) {
	userID := middleware.GetUserID(c)
	exportID, err := uuid.Parse(c.Param("export_id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, models.APIError{Code: "bad_request", Message: "invalid export_id"})
		return
	}
	var body struct {
		Days int `json:"days" binding:"required,min=1,max=365"`
	}
	if err := c.ShouldBindJSON(&body); err != nil {
		c.JSON(http.StatusBadRequest, models.APIError{Code: "bad_request", Message: err.Error()})
		return
	}
	newDate, err := h.store.ExtendExportDeleteDate(c.Request.Context(), exportID, userID, body.Days)
	if err != nil {
		c.JSON(http.StatusNotFound, models.APIError{Code: "not_found", Message: err.Error()})
		return
	}
	c.JSON(http.StatusOK, gin.H{"new_auto_delete_date": newDate})
}

// GET /v1/exports/:export_id/download-url
func (h *ExportHandler) DownloadURL(c *gin.Context) {
	userID := middleware.GetUserID(c)
	exportID, err := uuid.Parse(c.Param("export_id"))
	if err != nil {
		c.JSON(http.StatusBadRequest, models.APIError{Code: "bad_request", Message: "invalid export_id"})
		return
	}
	exp, err := h.store.GetExportByID(c.Request.Context(), exportID, userID)
	if err != nil {
		c.JSON(http.StatusNotFound, models.APIError{Code: "not_found", Message: err.Error()})
		return
	}
	// Generate presigned URL (15 min TTL)
	expiry := 15 * time.Minute
	url, err := h.minio.PresignedGetObject(context.Background(), h.bucket, exp.Path, expiry, nil)
	if err != nil {
		c.JSON(http.StatusInternalServerError, models.APIError{Code: "internal_error", Message: "could not generate download URL"})
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"url":        url.String(),
		"expires_at": time.Now().Add(expiry),
	})
}
