package convert

import (
	"fmt"
	"strings"
)

// DVDNTSCPreset creates a ConvertConfig optimized for DVD-Video NTSC output
// This preset generates MPEG-2 program streams (.mpg) that are:
// - Fully DVD-compliant (720x480@29.97fps NTSC)
// - Region-free
// - Compatible with DVDStyler and professional DVD authoring software
// - Playable on PS2, standalone DVD players, and modern systems
func DVDNTSCPreset() ConvertConfig {
	return ConvertConfig{
		SelectedFormat:   FormatOption{Label: "MPEG-2 (DVD NTSC)", Ext: ".mpg", VideoCodec: "mpeg2video"},
		Quality:          "Standard (CRF 23)", // DVD uses bitrate control, not CRF
		Mode:             "Advanced",
		VideoCodec:       "MPEG-2",
		EncoderPreset:    "medium",
		BitrateMode:      "CBR", // DVD requires constant bitrate
		VideoBitrate:     "6000k",
		TargetResolution: "720x480",
		FrameRate:        "29.97",
		PixelFormat:      "yuv420p",
		HardwareAccel:    "none", // MPEG-2 encoding doesn't benefit much from GPU acceleration
		AudioCodec:       "AC-3",
		AudioBitrate:     "192k",
		AudioChannels:    "Stereo",
		InverseTelecine:  false, // Set based on source
		AspectHandling:   "letterbox",
		OutputAspect:     "source",
	}
}

// DVDValidationWarning represents a validation issue with DVD encoding
type DVDValidationWarning struct {
	Severity string // "info", "warning", "error"
	Message  string
	Action   string // What will be done to fix it
}

// ValidateDVDNTSC performs comprehensive validation on a video for DVD-NTSC output
func ValidateDVDNTSC(src *VideoSource, cfg ConvertConfig) []DVDValidationWarning {
	var warnings []DVDValidationWarning

	if src == nil {
		warnings = append(warnings, DVDValidationWarning{
			Severity: "error",
			Message:  "No video source selected",
			Action:   "Cannot proceed without a source video",
		})
		return warnings
	}

	// 1. Framerate Validation
	if src.FrameRate > 0 {
		normalizedRate := normalizeFrameRate(src.FrameRate)
		switch normalizedRate {
		case "23.976":
			warnings = append(warnings, DVDValidationWarning{
				Severity: "warning",
				Message:  fmt.Sprintf("Input framerate is %.2f fps (23.976p)", src.FrameRate),
				Action:   "Will apply 3:2 pulldown to convert to 29.97fps (requires interlacing)",
			})
		case "24.0":
			warnings = append(warnings, DVDValidationWarning{
				Severity: "warning",
				Message:  fmt.Sprintf("Input framerate is %.2f fps (24p)", src.FrameRate),
				Action:   "Will apply 3:2 pulldown to convert to 29.97fps (requires interlacing)",
			})
		case "29.97":
			// Perfect - no warning
		case "30.0":
			warnings = append(warnings, DVDValidationWarning{
				Severity: "info",
				Message:  fmt.Sprintf("Input framerate is %.2f fps (30p)", src.FrameRate),
				Action:   "Will convert to 29.97fps (NTSC standard)",
			})
		case "59.94":
			warnings = append(warnings, DVDValidationWarning{
				Severity: "warning",
				Message:  fmt.Sprintf("Input framerate is %.2f fps (59.94p)", src.FrameRate),
				Action:   "Will decimate to 29.97fps (dropping every other frame)",
			})
		case "60.0":
			warnings = append(warnings, DVDValidationWarning{
				Severity: "warning",
				Message:  fmt.Sprintf("Input framerate is %.2f fps (60p)", src.FrameRate),
				Action:   "Will decimate to 29.97fps (dropping every other frame)",
			})
		case "vfr":
			warnings = append(warnings, DVDValidationWarning{
				Severity: "error",
				Message:  "Input is Variable Frame Rate (VFR)",
				Action:   "Will force constant frame rate at 29.97fps (may cause sync issues)",
			})
		default:
			if src.FrameRate < 15 {
				warnings = append(warnings, DVDValidationWarning{
					Severity: "error",
					Message:  fmt.Sprintf("Input framerate is %.2f fps (too low for DVD)", src.FrameRate),
					Action:   "Cannot encode - DVD requires minimum 23.976fps",
				})
			} else if src.FrameRate > 60 {
				warnings = append(warnings, DVDValidationWarning{
					Severity: "warning",
					Message:  fmt.Sprintf("Input framerate is %.2f fps (higher than DVD standard)", src.FrameRate),
					Action:   "Will decimate to 29.97fps",
				})
			}
		}
	}

	// 2. Resolution Validation
	if src.Width != 720 || src.Height != 480 {
		warnings = append(warnings, DVDValidationWarning{
			Severity: "info",
			Message:  fmt.Sprintf("Input resolution is %dx%d (not 720x480)", src.Width, src.Height),
			Action:   "Will scale to 720x480 with aspect-ratio correction",
		})
	}

	// 3. Audio Sample Rate Validation
	if src.AudioRate > 0 {
		if src.AudioRate != 48000 {
			warnings = append(warnings, DVDValidationWarning{
				Severity: "warning",
				Message:  fmt.Sprintf("Audio sample rate is %d Hz (not 48 kHz)", src.AudioRate),
				Action:   "Will resample to 48 kHz (DVD standard)",
			})
		}
	}

	// 4. Interlacing Analysis
	if !src.IsProgressive() {
		warnings = append(warnings, DVDValidationWarning{
			Severity: "info",
			Message:  "Input is interlaced",
			Action:   "Will encode as interlaced (progressive deinterlacing not applied)",
		})
	} else {
		warnings = append(warnings, DVDValidationWarning{
			Severity: "info",
			Message:  "Input is progressive",
			Action:   "Will encode as progressive (no interlacing applied)",
		})
	}

	// 5. Bitrate Validation
	maxDVDBitrate := 9000.0
	if strings.HasSuffix(cfg.VideoBitrate, "k") {
		bitrateStr := strings.TrimSuffix(cfg.VideoBitrate, "k")
		var bitrate float64
		if _, err := fmt.Sscanf(bitrateStr, "%f", &bitrate); err == nil {
			if bitrate > maxDVDBitrate {
				warnings = append(warnings, DVDValidationWarning{
					Severity: "error",
					Message:  fmt.Sprintf("Video bitrate %s exceeds DVD maximum of %.0fk", cfg.VideoBitrate, maxDVDBitrate),
					Action:   "Will cap at 9000k (PS2 safe limit)",
				})
			}
		}
	}

	// 6. Audio Codec Validation
	if cfg.AudioCodec != "AC-3" && cfg.AudioCodec != "Copy" {
		warnings = append(warnings, DVDValidationWarning{
			Severity: "warning",
			Message:  fmt.Sprintf("Audio codec is %s (DVD standard is AC-3)", cfg.AudioCodec),
			Action:   "Recommend using AC-3 for maximum compatibility",
		})
	}

	// 7. Aspect Ratio Validation
	if src.Width > 0 && src.Height > 0 {
		sourceAspect := float64(src.Width) / float64(src.Height)
		validAspects := map[string]float64{
			"4:3":  1.333,
			"16:9": 1.778,
		}
		found := false
		for _, ratio := range validAspects {
			// Allow 1% tolerance
			if diff := sourceAspect - ratio; diff < 0 && diff > -0.02 || diff >= 0 && diff < 0.02 {
				found = true
				break
			}
		}
		if !found {
			warnings = append(warnings, DVDValidationWarning{
				Severity: "warning",
				Message:  fmt.Sprintf("Aspect ratio is %.2f:1 (not standard 4:3 or 16:9)", sourceAspect),
				Action:   fmt.Sprintf("Will apply %s with aspect correction", cfg.AspectHandling),
			})
		}
	}

	return warnings
}

// normalizeFrameRate categorizes a framerate value
func normalizeFrameRate(rate float64) string {
	if rate < 15 {
		return "low"
	}
	// Check for common framerates with tolerance
	checks := []struct {
		name     string
		min, max float64
	}{
		{"23.976", 23.9, 24.0},
		{"24.0", 23.99, 24.01},
		{"29.97", 29.9, 30.0},
		{"30.0", 30.0, 30.01},
		{"59.94", 59.9, 60.0},
		{"60.0", 60.0, 60.01},
	}
	for _, c := range checks {
		if rate >= c.min && rate <= c.max {
			return c.name
		}
	}
	return fmt.Sprintf("%.2f", rate)
}

// BuildDVDFFmpegArgs constructs FFmpeg arguments for DVD-NTSC encoding
// This ensures all parameters are DVD-compliant and correctly formatted
func BuildDVDFFmpegArgs(inputPath, outputPath string, cfg ConvertConfig, src *VideoSource) []string {
	args := []string{
		"-y",
		"-hide_banner",
		"-loglevel", "error",
		"-i", inputPath,
	}

	// Video filters
	var vf []string

	// Scaling to DVD resolution with aspect preservation
	if src.Width != 720 || src.Height != 480 {
		// Use scale filter with aspect ratio handling
		vf = append(vf, "scale=720:480:force_original_aspect_ratio=1")

		// Add aspect ratio handling (pad/crop)
		switch cfg.AspectHandling {
		case "letterbox":
			vf = append(vf, "pad=720:480:(ow-iw)/2:(oh-ih)/2")
		case "pillarbox":
			vf = append(vf, "pad=720:480:(ow-iw)/2:(oh-ih)/2")
		}
	}

	// Set Display Aspect Ratio (DAR) - tell decoder the aspect
	if cfg.OutputAspect == "16:9" {
		vf = append(vf, "setdar=16/9")
	} else {
		vf = append(vf, "setdar=4/3")
	}

	// Set Sample Aspect Ratio (SAR) - DVD standard
	vf = append(vf, "setsar=1")

	// Framerate - always to 29.97 for NTSC
	vf = append(vf, "fps=30000/1001")

	if len(vf) > 0 {
		args = append(args, "-vf", strings.Join(vf, ","))
	}

	// Video codec - MPEG-2 for DVD
	args = append(args,
		"-c:v", "mpeg2video",
		"-r", "30000/1001",
		"-b:v", "6000k",
		"-maxrate", "9000k",
		"-bufsize", "1835k",
		"-g", "15", // GOP size
		"-flags", "+mv4", // Use four motion vector candidates
		"-pix_fmt", "yuv420p",
	)

	// Optional: Interlacing flags
	// If the source is interlaced, we can preserve that:
	if !src.IsProgressive() {
		args = append(args, "-flags", "+ilme+ildct")
	}

	// Audio codec - AC-3 (Dolby Digital)
	args = append(args,
		"-c:a", "ac3",
		"-b:a", "192k",
		"-ar", "48000",
		"-ac", "2",
	)

	// Progress monitoring
	args = append(args,
		"-progress", "pipe:1",
		"-nostats",
		outputPath,
	)

	return args
}

// DVDNTSCInfo returns a human-readable description of the DVD-NTSC preset
func DVDNTSCInfo() string {
	return `DVD-NTSC (Region-Free) Output

This preset generates professional-grade MPEG-2 program streams (.mpg) compatible with:
- DVD authoring software (DVDStyler, Adobe Encore, etc.)
- PlayStation 2 and standalone DVD players
- Modern media centers and PC-based DVD players

Technical Specifications:
  Video Codec:        MPEG-2 (mpeg2video)
  Container:          MPEG Program Stream (.mpg)
  Resolution:         720x480 (NTSC Full D1)
  Frame Rate:         29.97 fps (30000/1001)
  Aspect Ratio:       4:3 or 16:9 (user-selectable)
  Bitrate:            6000 kbps (average), 9000 kbps (max)
  GOP Size:           15 frames
  Interlacing:        Progressive or Interlaced (auto-detected)

Audio Codec:         AC-3 (Dolby Digital)
  Channels:          Stereo (2.0)
  Bitrate:           192 kbps
  Sample Rate:       48 kHz (mandatory)

The output is guaranteed to be importable directly into DVDStyler without
re-encoding warnings, and will play flawlessly on PS2 and standalone players.`
}
