package handlers

import (
	"Yimaru-Backend/internal/domain"
	"Yimaru-Backend/internal/pkgs/vimeo"
	"fmt"
	"strconv"

	"github.com/gofiber/fiber/v2"
)

type CreatePullUploadRequest struct {
	Name        string `json:"name" validate:"required"`
	Description string `json:"description"`
	SourceURL   string `json:"source_url" validate:"required,url"`
	FileSize    int64  `json:"file_size" validate:"required,gt=0"`
}

type CreateTusUploadRequest struct {
	Name        string `json:"name" validate:"required"`
	Description string `json:"description"`
	FileSize    int64  `json:"file_size" validate:"required,gt=0"`
}

type GetEmbedCodeRequest struct {
	VideoID    string `json:"video_id" validate:"required"`
	Width      int    `json:"width"`
	Height     int    `json:"height"`
	Autoplay   bool   `json:"autoplay"`
	Loop       bool   `json:"loop"`
	Muted      bool   `json:"muted"`
	Background bool   `json:"background"`
}

type VimeoVideoResponse struct {
	VimeoID         string `json:"vimeo_id"`
	URI             string `json:"uri"`
	Name            string `json:"name"`
	Description     string `json:"description"`
	Duration        int    `json:"duration"`
	Width           int    `json:"width"`
	Height          int    `json:"height"`
	Link            string `json:"link"`
	EmbedURL        string `json:"embed_url"`
	EmbedHTML       string `json:"embed_html"`
	ThumbnailURL    string `json:"thumbnail_url"`
	Status          string `json:"status"`
	TranscodeStatus string `json:"transcode_status"`
}

type VimeoUploadResponse struct {
	VimeoID    string `json:"vimeo_id"`
	URI        string `json:"uri"`
	Link       string `json:"link"`
	UploadLink string `json:"upload_link,omitempty"`
	Status     string `json:"status"`
}

type VimeoEmbedResponse struct {
	VideoID   string `json:"video_id"`
	EmbedURL  string `json:"embed_url"`
	EmbedHTML string `json:"embed_html"`
}

// GetVimeoVideo godoc
// @Summary Get video information from Vimeo
// @Description Retrieves video details from Vimeo by video ID
// @Tags Vimeo
// @Accept json
// @Produce json
// @Param video_id path string true "Vimeo Video ID"
// @Success 200 {object} VimeoVideoResponse
// @Failure 400 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/vimeo/videos/{video_id} [get]
func (h *Handler) GetVimeoVideo(c *fiber.Ctx) error {
	if h.vimeoSvc == nil {
		return c.Status(fiber.StatusServiceUnavailable).JSON(domain.ErrorResponse{
			Message: "Vimeo service is not configured",
			Error:   "Vimeo service is not enabled or missing access token",
		})
	}

	videoID := c.Params("video_id")
	if videoID == "" {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "video_id is required",
			Error:   "video_id path parameter is empty",
		})
	}

	info, err := h.vimeoSvc.GetVideoInfo(c.Context(), videoID)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to get video info",
			Error:   err.Error(),
		})
	}

	return c.JSON(domain.Response{
		Message: "Video retrieved successfully",
		Data: VimeoVideoResponse{
			VimeoID:         info.VimeoID,
			URI:             info.URI,
			Name:            info.Name,
			Description:     info.Description,
			Duration:        info.Duration,
			Width:           info.Width,
			Height:          info.Height,
			Link:            info.Link,
			EmbedURL:        info.EmbedURL,
			EmbedHTML:       info.EmbedHTML,
			ThumbnailURL:    info.ThumbnailURL,
			Status:          info.Status,
			TranscodeStatus: info.TranscodeStatus,
		},
		Success:    true,
		StatusCode: fiber.StatusOK,
	})
}

// CreatePullUpload godoc
// @Summary Create a pull upload to Vimeo
// @Description Initiates a pull upload where Vimeo fetches the video from a URL
// @Tags Vimeo
// @Accept json
// @Produce json
// @Param request body CreatePullUploadRequest true "Pull Upload Request"
// @Success 201 {object} VimeoUploadResponse
// @Failure 400 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/vimeo/uploads/pull [post]
func (h *Handler) CreatePullUpload(c *fiber.Ctx) error {
	if h.vimeoSvc == nil {
		return c.Status(fiber.StatusServiceUnavailable).JSON(domain.ErrorResponse{
			Message: "Vimeo service is not configured",
			Error:   "Vimeo service is not configured",
		})
	}

	var req CreatePullUploadRequest
	if err := c.BodyParser(&req); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Invalid request body",
			Error:   err.Error(),
		})
	}

	if valErrs, ok := h.validator.Validate(c, req); !ok {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Failed to validate request body",
			Error:   fmt.Sprintf("%v", valErrs),
		})
	}

	result, err := h.vimeoSvc.CreatePullUpload(c.Context(), req.Name, req.Description, req.SourceURL, req.FileSize)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to create Vimeo upload",
			Error:   err.Error(),
		})
	}

	return c.Status(fiber.StatusCreated).JSON(domain.Response{
		Message:    "Vimeo upload created successfully",
		Data:       result,
		Success:    true,
		StatusCode: fiber.StatusCreated,
	})
}

// CreateTusUpload godoc
// @Summary Create a TUS resumable upload to Vimeo
// @Description Initiates a TUS resumable upload and returns the upload link
// @Tags Vimeo
// @Accept json
// @Produce json
// @Param request body CreateTusUploadRequest true "TUS Upload Request"
// @Success 201 {object} VimeoUploadResponse
// @Failure 400 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/vimeo/uploads/tus [post]
func (h *Handler) CreateTusUpload(c *fiber.Ctx) error {
	if h.vimeoSvc == nil {
		return c.Status(fiber.StatusServiceUnavailable).JSON(domain.ErrorResponse{
			Message: "Vimeo service is not configured",
			Error:   "Vimeo service is not enabled or missing access token",
		})
	}

	var req CreateTusUploadRequest
	if err := c.BodyParser(&req); err != nil {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Invalid request body",
			Error:   err.Error(),
		})
	}

	if valErrs, ok := h.validator.Validate(c, req); !ok {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "Failed to validate request body",
			Error:   fmt.Sprintf("%v", valErrs),
		})
	}

	result, err := h.vimeoSvc.CreateTusUpload(c.Context(), req.Name, req.Description, req.FileSize)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to create Vimeo TUS upload",
			Error:   err.Error(),
		})
	}

	return c.Status(fiber.StatusCreated).JSON(domain.Response{
		Message:    "Vimeo TUS upload created successfully",
		Data:       result,
		Success:    true,
		StatusCode: fiber.StatusCreated,
	})
}

// GetEmbedCode godoc
// @Summary Get embed code for a Vimeo video
// @Description Generates an embeddable player iframe for the video
// @Tags Vimeo
// @Accept json
// @Produce json
// @Param video_id path string true "Vimeo Video ID"
// @Param width query int false "Player width" default(640)
// @Param height query int false "Player height" default(360)
// @Param autoplay query bool false "Autoplay video"
// @Param loop query bool false "Loop video"
// @Param muted query bool false "Mute video"
// @Param background query bool false "Background mode (no controls)"
// @Success 200 {object} VimeoEmbedResponse
// @Failure 400 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/vimeo/videos/{video_id}/embed [get]
func (h *Handler) GetEmbedCode(c *fiber.Ctx) error {
	if h.vimeoSvc == nil {
		return c.Status(fiber.StatusServiceUnavailable).JSON(domain.ErrorResponse{
			Message: "Vimeo service is not configured",
			Error:   "Vimeo service is not configured",
		})
	}

	videoID := c.Params("video_id")
	if videoID == "" {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "video_id is required",
			Error:   "video_id is empty",
		})
	}

	width, _ := strconv.Atoi(c.Query("width", "640"))
	height, _ := strconv.Atoi(c.Query("height", "360"))
	autoplay := c.Query("autoplay") == "true"
	loop := c.Query("loop") == "true"
	muted := c.Query("muted") == "true"
	background := c.Query("background") == "true"

	opts := &vimeo.EmbedOptions{
		Autoplay:   autoplay,
		Loop:       loop,
		Muted:      muted,
		Background: background,
		Title:      true,
		Byline:     true,
		Portrait:   true,
	}

	embedHTML, err := h.vimeoSvc.GetEmbedCode(c.Context(), videoID, width, height, opts)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to get embed code",
			Error:   err.Error(),
		})
	}

	embedURL := h.vimeoSvc.GeneratePlayerURL(videoID, opts)

	return c.JSON(domain.Response{
		Message: "Embed code retrieved successfully",
		Data: VimeoEmbedResponse{
			VideoID:   videoID,
			EmbedURL:  embedURL,
			EmbedHTML: embedHTML,
		},
		Success:    true,
		StatusCode: fiber.StatusOK,
	})
}

// DeleteVimeoVideo godoc
// @Summary Delete a video from Vimeo
// @Description Deletes a video from the Vimeo account
// @Tags Vimeo
// @Accept json
// @Produce json
// @Param video_id path string true "Vimeo Video ID"
// @Success 204
// @Failure 400 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/vimeo/videos/{video_id} [delete]
func (h *Handler) DeleteVimeoVideo(c *fiber.Ctx) error {
	if h.vimeoSvc == nil {
		return c.Status(fiber.StatusServiceUnavailable).JSON(domain.ErrorResponse{
			Message: "Vimeo service is not configured",
			Error:   "Vimeo service is not enabled or missing access token",
		})
	}

	videoID := c.Params("video_id")
	if videoID == "" {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "video_id is required",
			Error:   "video_id path parameter is empty",
		})
	}

	if err := h.vimeoSvc.DeleteVideo(c.Context(), videoID); err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to delete video",
			Error:   err.Error(),
		})
	}

	return c.Status(fiber.StatusOK).JSON(domain.Response{
		Message:    "Video deleted successfully",
		Success:    true,
		StatusCode: fiber.StatusOK,
	})
}

// GetTranscodeStatus godoc
// @Summary Get transcode status of a Vimeo video
// @Description Returns the current transcoding status of a video
// @Tags Vimeo
// @Accept json
// @Produce json
// @Param video_id path string true "Vimeo Video ID"
// @Success 200 {object} map[string]string
// @Failure 400 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/vimeo/videos/{video_id}/status [get]
func (h *Handler) GetTranscodeStatus(c *fiber.Ctx) error {
	if h.vimeoSvc == nil {
		return c.Status(fiber.StatusServiceUnavailable).JSON(domain.ErrorResponse{
			Message: "Vimeo service is not configured",
			Error:   "Vimeo service is not enabled or missing access token",
		})
	}

	videoID := c.Params("video_id")
	if videoID == "" {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "video_id is required",
			Error:   "video_id path parameter is empty",
		})
	}

	status, err := h.vimeoSvc.GetTranscodeStatus(c.Context(), videoID)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to get transcode status",
			Error:   err.Error(),
		})
	}

	return c.JSON(domain.Response{
		Message: "Transcode status retrieved successfully",
		Data: fiber.Map{
			"video_id": videoID,
			"status":   status,
		},
		Success:    true,
		StatusCode: fiber.StatusOK,
	})
}

// GetOEmbed godoc
// @Summary Get oEmbed data for a Vimeo URL
// @Description Fetches oEmbed metadata for a Vimeo video URL
// @Tags Vimeo
// @Accept json
// @Produce json
// @Param url query string true "Vimeo video URL"
// @Param width query int false "Desired width"
// @Param height query int false "Desired height"
// @Success 200 {object} vimeo.OEmbedResponse
// @Failure 400 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/vimeo/oembed [get]
func (h *Handler) GetOEmbed(c *fiber.Ctx) error {
	if h.vimeoSvc == nil {
		return c.Status(fiber.StatusServiceUnavailable).JSON(domain.ErrorResponse{
			Message: "Vimeo service is not configured",
			Error:   "Vimeo service is not enabled or missing access token",
		})
	}

	vimeoURL := c.Query("url")
	if vimeoURL == "" {
		return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
			Message: "url query parameter is required",
			Error:   "url query parameter is empty",
		})
	}

	width, _ := strconv.Atoi(c.Query("width", "0"))
	height, _ := strconv.Atoi(c.Query("height", "0"))

	oembed, err := h.vimeoSvc.GetOEmbed(c.Context(), vimeoURL, width, height)
	if err != nil {
		return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
			Message: "Failed to get oEmbed data",
			Error:   err.Error(),
		})
	}

	return c.JSON(domain.Response{
		Message:    "oEmbed data retrieved successfully",
		Data:       oembed,
		Success:    true,
		StatusCode: fiber.StatusOK,
	})
}
