package api

import (
	"context"
	"encoding/json"
	"fmt"
	"log/slog"
	"net/http"
	"strconv"
	"strings"
	"time"

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

func searchReleases(svc *service.SearchService) echo.HandlerFunc {
	return func(c echo.Context) error {
		ctx, cancel := context.WithTimeout(c.Request().Context(), 30*time.Second)
		defer cancel()

		query := c.QueryParam("query")
		if query == "" {
			return c.JSON(http.StatusBadRequest, map[string]string{"error": "query parameter is required"})
		}

		mediaType := c.QueryParam("media_type")

		var indexerIDs []int64
		if ids := c.QueryParam("indexer_ids"); ids != "" {
			for _, idStr := range strings.Split(ids, ",") {
				idStr = strings.TrimSpace(idStr)
				if id, err := strconv.ParseInt(idStr, 10, 64); err == nil {
					indexerIDs = append(indexerIDs, id)
				}
			}
		}

		req := service.SearchRequest{
			Query:      query,
			MediaType:  mediaType,
			IndexerIDs: indexerIDs,
		}

		results, err := svc.Search(ctx, req)
		if err != nil {
			return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
		}

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

func grabRelease(svc *service.SearchService, dcSvc *service.DownloadClientService, queueSvc *service.QueueService, safetySvc *service.SafetyService, activitySvc *service.ActivityService) echo.HandlerFunc {
	return func(c echo.Context) error {
		ctx, cancel := context.WithTimeout(c.Request().Context(), 30*time.Second)
		defer cancel()

		var req service.GrabRequest
		if err := c.Bind(&req); err != nil {
			return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request body"})
		}

		if req.DownloadURL == "" {
			return c.JSON(http.StatusBadRequest, map[string]string{"error": "download_url is required"})
		}
		if req.Title == "" {
			return c.JSON(http.StatusBadRequest, map[string]string{"error": "title is required"})
		}
		if req.MediaID == 0 {
			return c.JSON(http.StatusBadRequest, map[string]string{"error": "media_id is required"})
		}

		// Safety check: block dangerous file extensions before download
		if safetySvc != nil {
			block := safetySvc.Check(req.Title, req.DownloadURL)
			if block != nil {
				if activitySvc != nil {
					activitySvc.LogAsync(service.LogEntry{
						EventType:   "safety_block",
						MediaID:     &req.MediaID,
						MediaType:   &req.MediaType,
						Title:       req.Title,
						Description: &block.Reason,
						Data:        json.RawMessage(fmt.Sprintf(`{"extension":"%s","indexer":"%s"}`, block.MatchedExtension, req.IndexerName)),
					})
				}
				return c.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
					"error":   block.Reason,
					"blocked": true,
				})
			}
		}

		result, err := svc.Grab(ctx, req, dcSvc)
		if err != nil {
			return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
		}

		qualityJSON, _ := json.Marshal(req.Quality)
		_, err = queueSvc.CreateQueueEntry(ctx, service.CreateQueueEntryRequest{
			MediaID:        req.MediaID,
			MediaType:      req.MediaType,
			ReleaseTitle:   req.Title,
			Indexer:        req.IndexerName,
			DownloadClient: result.ClientName,
			Quality:        qualityJSON,
			Protocol:       result.Protocol,
			DownloadID:     result.DownloadID,
		})
		if err != nil {
			slog.Error("failed to create queue entry", "error", err)
		}

		// Log successful grab activity
		if activitySvc != nil {
			activitySvc.LogAsync(service.LogEntry{
				EventType:   "grab",
				MediaID:     &req.MediaID,
				MediaType:   &req.MediaType,
				Title:       fmt.Sprintf("Grabbed %s", req.Title),
				Description: &req.IndexerName,
				Data:        json.RawMessage(fmt.Sprintf(`{"release":"%s","client":"%s","protocol":"%s"}`, req.Title, result.ClientName, result.Protocol)),
			})
		}

		return c.JSON(http.StatusCreated, map[string]interface{}{
			"queue_id":    result.QueueID,
			"download_id": result.DownloadID,
			"client":      result.ClientName,
			"protocol":    result.Protocol,
		})
	}
}
