package api

import (
	"context"
	"log/slog"
	"net/http"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/TopherMayor/unified-media-manager/internal/service"
	"github.com/labstack/echo/v4"
)

func searchSubtitles(subSvc *service.SubtitleService, mediaSvc *service.MediaService) echo.HandlerFunc {
	return func(c echo.Context) error {
		ctx, cancel := context.WithTimeout(c.Request().Context(), 15*time.Second)
		defer cancel()

		id, err := strconv.ParseInt(c.Param("id"), 10, 64)
		if err != nil {
			return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid id"})
		}

		mediaType := c.Param("type")
		if mediaType == "" {
			return c.JSON(http.StatusBadRequest, map[string]string{"error": "media type required"})
		}

		detail, err := mediaSvc.GetByID(ctx, id, mediaType)
		if err != nil {
			return c.JSON(http.StatusNotFound, map[string]string{"error": "media not found"})
		}

		langsParam := c.QueryParam("languages")
		if langsParam == "" {
			langsParam = "en"
		}
		langs := strings.Split(langsParam, ",")

		hi := c.QueryParam("hi") == "true"
		forced := c.QueryParam("forced") == "true"

		results, err := subSvc.Search(ctx, detail.Media.Title, service.SubtitleSearchOptions{
			LanguageCodes: langs,
			HI:            hi,
			Forced:        forced,
		})
		if err != nil {
			slog.Error("subtitle search failed", "error", err)
			return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
		}

		return c.JSON(http.StatusOK, map[string]interface{}{
			"data": results,
		})
	}
}

type downloadSubtitleRequest struct {
	SubtitleID   string `json:"subtitle_id"`
	LanguageCode string `json:"language_code"`
	HI           bool   `json:"hi"`
	Forced       bool   `json:"forced"`
}

func downloadSubtitle(subSvc *service.SubtitleService, mediaSvc *service.MediaService) echo.HandlerFunc {
	return func(c echo.Context) error {
		ctx, cancel := context.WithTimeout(c.Request().Context(), 15*time.Second)
		defer cancel()

		id, err := strconv.ParseInt(c.Param("id"), 10, 64)
		if err != nil {
			return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid id"})
		}

		mediaType := c.Param("type")
		if mediaType == "" {
			return c.JSON(http.StatusBadRequest, map[string]string{"error": "media type required"})
		}

		var req downloadSubtitleRequest
		if err := c.Bind(&req); err != nil {
			return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
		}
		if req.SubtitleID == "" {
			return c.JSON(http.StatusBadRequest, map[string]string{"error": "subtitle_id required"})
		}
		if req.LanguageCode == "" {
			req.LanguageCode = "en"
		}

		detail, err := mediaSvc.GetByID(ctx, id, mediaType)
		if err != nil {
			return c.JSON(http.StatusNotFound, map[string]string{"error": "media not found"})
		}

		targetDir := ""
		if detail.Media.RootFolderID != nil {
			targetDir = filepath.Join("/", "data", mediaType)
		}
		if targetDir == "" {
			targetDir = filepath.Join("/", "data", mediaType, "subtitles")
		}

		season := 0
		episode := 0
		baseName := service.BuildSubtitleBaseName(detail.Media.Title, detail.Media.Year, season, episode)

		result, err := subSvc.Download(ctx, req.SubtitleID, targetDir, baseName, req.LanguageCode, req.HI, req.Forced)
		if err != nil {
			slog.Error("subtitle download failed", "error", err)
			return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
		}

		return c.JSON(http.StatusOK, result)
	}
}

func extractSubtitles(subSvc *service.SubtitleService, mediaSvc *service.MediaService) echo.HandlerFunc {
	return func(c echo.Context) error {
		ctx, cancel := context.WithTimeout(c.Request().Context(), 30*time.Second)
		defer cancel()

		id, err := strconv.ParseInt(c.Param("id"), 10, 64)
		if err != nil {
			return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid id"})
		}

		mediaType := c.Param("type")
		if mediaType == "" {
			return c.JSON(http.StatusBadRequest, map[string]string{"error": "media type required"})
		}

		detail, err := mediaSvc.GetByID(ctx, id, mediaType)
		if err != nil {
			return c.JSON(http.StatusNotFound, map[string]string{"error": "media not found"})
		}

		var allFiles []service.SubtitleFile
		for _, file := range detail.Files {
			season := 0
			episode := 0
			baseName := service.BuildSubtitleBaseName(detail.Media.Title, detail.Media.Year, season, episode)

			extracted, err := subSvc.ExtractSubtitles(ctx, file.Path, filepath.Dir(file.Path), baseName)
			if err != nil {
				slog.Error("subtitle extraction failed", "error", err, "file", file.Path)
				continue
			}
			allFiles = append(allFiles, extracted...)
		}

		return c.JSON(http.StatusOK, map[string]interface{}{
			"data": allFiles,
		})
	}
}
