package video

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
)

// ExtractThumbnail extracts a thumbnail from a video file.
// Returns the thumbnail image data as JPEG.
func ExtractThumbnail(ctx context.Context, videoData []byte) ([]byte, error) {
	// Write video to temp file
	tmpDir, err := os.MkdirTemp("", "lookbook-video-*")
	if err != nil {
		return nil, fmt.Errorf("create temp dir: %w", err)
	}
	defer os.RemoveAll(tmpDir)

	inputPath := filepath.Join(tmpDir, "input")
	outputPath := filepath.Join(tmpDir, "thumbnail.jpg")

	if err := os.WriteFile(inputPath, videoData, 0600); err != nil {
		return nil, fmt.Errorf("write temp video: %w", err)
	}

	// Extract thumbnail at 1 second mark
	cmd := exec.CommandContext(ctx, "ffmpeg",
		"-i", inputPath,
		"-ss", "00:00:01",
		"-vframes", "1",
		"-vf", "scale='min(1280,iw)':'min(720,ih)':force_original_aspect_ratio=decrease",
		"-q:v", "2",
		"-y",
		outputPath,
	)

	var stderr bytes.Buffer
	cmd.Stderr = &stderr

	if err := cmd.Run(); err != nil {
		return nil, fmt.Errorf("ffmpeg thumbnail: %w: %s", err, stderr.String())
	}

	thumbnail, err := os.ReadFile(outputPath)
	if err != nil {
		return nil, fmt.Errorf("read thumbnail: %w", err)
	}

	return thumbnail, nil
}

// TranscodeToMP4 transcodes a video to H.264 MP4 format.
// Returns the transcoded video data.
func TranscodeToMP4(ctx context.Context, videoData []byte, contentType string) ([]byte, error) {
	// If already MP4 with H.264, we might skip transcoding
	// For simplicity, we always transcode to ensure compatibility

	tmpDir, err := os.MkdirTemp("", "lookbook-video-*")
	if err != nil {
		return nil, fmt.Errorf("create temp dir: %w", err)
	}
	defer os.RemoveAll(tmpDir)

	inputPath := filepath.Join(tmpDir, "input")
	outputPath := filepath.Join(tmpDir, "output.mp4")

	if err := os.WriteFile(inputPath, videoData, 0600); err != nil {
		return nil, fmt.Errorf("write temp video: %w", err)
	}

	// Transcode to H.264 MP4
	cmd := exec.CommandContext(ctx, "ffmpeg",
		"-i", inputPath,
		"-c:v", "libx264",
		"-preset", "medium",
		"-crf", "23",
		"-c:a", "aac",
		"-b:a", "128k",
		"-movflags", "+faststart",
		"-y",
		outputPath,
	)

	var stderr bytes.Buffer
	cmd.Stderr = &stderr

	if err := cmd.Run(); err != nil {
		return nil, fmt.Errorf("ffmpeg transcode: %w: %s", err, stderr.String())
	}

	output, err := os.ReadFile(outputPath)
	if err != nil {
		return nil, fmt.Errorf("read transcoded: %w", err)
	}

	return output, nil
}

// ProcessVideo processes an uploaded video: transcodes to MP4 and extracts thumbnail.
// Returns (transcodedData, thumbnailData, error).
func ProcessVideo(ctx context.Context, videoData []byte, contentType string) ([]byte, []byte, error) {
	// Extract thumbnail first (from original, often has better quality)
	thumbnail, err := ExtractThumbnail(ctx, videoData)
	if err != nil {
		return nil, nil, fmt.Errorf("extract thumbnail: %w", err)
	}

	// Transcode to MP4
	transcoded, err := TranscodeToMP4(ctx, videoData, contentType)
	if err != nil {
		return nil, nil, fmt.Errorf("transcode: %w", err)
	}

	return transcoded, thumbnail, nil
}

// IsVideo checks if a content type is a video type.
func IsVideo(contentType string) bool {
	switch contentType {
	case "video/mp4", "video/webm", "video/quicktime", "video/x-msvideo",
		"video/x-matroska", "video/mpeg", "video/ogg", "video/3gpp":
		return true
	}
	return false
}

// IsImage checks if a content type is an image type.
func IsImage(contentType string) bool {
	switch contentType {
	case "image/jpeg", "image/png", "image/gif", "image/webp", "image/avif":
		return true
	}
	return false
}

// ReadUpload reads an uploaded file up to maxSize bytes.
func ReadUpload(r io.Reader, maxSize int64) ([]byte, error) {
	limited := io.LimitReader(r, maxSize+1)
	data, err := io.ReadAll(limited)
	if err != nil {
		return nil, err
	}
	if int64(len(data)) > maxSize {
		return nil, fmt.Errorf("file too large (max %d bytes)", maxSize)
	}
	return data, nil
}
