package cmd

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"

	"skraak/tools"
)

func printClipUsage() {
	fmt.Fprintf(os.Stderr, "Usage: skraak calls clip [options]\n\n")
	fmt.Fprintf(os.Stderr, "Generate audio clips and spectrogram images from .data file segments.\n\n")
	fmt.Fprintf(os.Stderr, "Options:\n")
	fmt.Fprintf(os.Stderr, "  --file <path>      Path to .data file (required if no --folder)\n")
	fmt.Fprintf(os.Stderr, "  --folder <path>    Path to folder containing .data files (required if no --file)\n")
	fmt.Fprintf(os.Stderr, "  --output <path>    Output folder for generated clips (required)\n")
	fmt.Fprintf(os.Stderr, "  --prefix <name>    Prefix for output filenames (required)\n")
	fmt.Fprintf(os.Stderr, "  --filter <name>    Filter by ML model name (optional)\n")
	fmt.Fprintf(os.Stderr, "  --species <name>   Filter by species, optionally with calltype (e.g. Kiwi, Kiwi+Duet)\n")
	fmt.Fprintf(os.Stderr, "  --certainty <int>  Filter by certainty value (0-100, optional)\n")
	fmt.Fprintf(os.Stderr, "  --size <int>       Spectrogram image size in pixels (224-896, default 224)\n")
	fmt.Fprintf(os.Stderr, "  --color            Apply L4 colormap to spectrogram (default: grayscale)\n")
	fmt.Fprintf(os.Stderr, "  --night            Only clip recordings made during solar night (requires --location)\n")
	fmt.Fprintf(os.Stderr, "  --day              Only clip recordings made during solar day (requires --location)\n")
	fmt.Fprintf(os.Stderr, "  --location <lat,lng[,tz]> GPS coordinates and optional IANA timezone\n")
	fmt.Fprintf(os.Stderr, "                     e.g. --location \"-36.85,174.76\" or --location \"-36.85,174.76,Pacific/Auckland\"\n")
	fmt.Fprintf(os.Stderr, "                     Required with --night or --day. Timezone defaults to UTC.\n")
	fmt.Fprintf(os.Stderr, "                     Not needed for AudioMoth data (UTC from WAV comment).\n")
	fmt.Fprintf(os.Stderr, "\nOutput files:\n")
	fmt.Fprintf(os.Stderr, "  <prefix>_<basename>_<start>_<end>.png   # spectrogram image\n")
	fmt.Fprintf(os.Stderr, "  <prefix>_<basename>_<start>_<end>.wav   # audio clip (16kHz if downsampled)\n")
	fmt.Fprintf(os.Stderr, "\nExamples:\n")
	fmt.Fprintf(os.Stderr, "  # Clip all segments from a single file\n")
	fmt.Fprintf(os.Stderr, "  skraak calls clip --file recording.data --output ./clips --prefix train\n\n")
	fmt.Fprintf(os.Stderr, "  # Clip only Kiwi segments with color spectrograms at 448px\n")
	fmt.Fprintf(os.Stderr, "  skraak calls clip --folder ./data --output ./clips --prefix kiwi \\\n")
	fmt.Fprintf(os.Stderr, "    --filter opensoundscape-kiwi-1.2 --species Kiwi --size 448 --color\n\n")
	fmt.Fprintf(os.Stderr, "  # Clip Kiwi Duet calls\n")
	fmt.Fprintf(os.Stderr, "  skraak calls clip --folder ./data --output ./clips --prefix duet \\\n")
	fmt.Fprintf(os.Stderr, "    --filter opensoundscape-kiwi-1.2 --species Kiwi+Duet\n")
}

// clipFlags holds the parsed CLI flags for calls clip
type clipFlags struct {
	file      string
	folder    string
	output    string
	prefix    string
	filter    string
	species   string
	size      int
	certainty int
	color     bool
	night     bool
	day       bool
	location  string
}

// parseClipArgs parses CLI arguments into clip flags using flag.FlagSet.
func parseClipArgs(args []string) clipFlags {
	fs := flag.NewFlagSet("calls clip", flag.ExitOnError)
	file := fs.String("file", "", "Path to .data file (required if no --folder)")
	folder := fs.String("folder", "", "Path to folder containing .data files (required if no --file)")
	output := fs.String("output", "", "Output folder for generated clips (required)")
	prefix := fs.String("prefix", "", "Prefix for output filenames (required)")
	filter := fs.String("filter", "", "Filter by ML model name")
	species := fs.String("species", "", "Filter by species, optionally with calltype")
	certainty := fs.Int("certainty", -1, "Filter by certainty value (0-100)")
	size := fs.Int("size", 0, "Spectrogram image size in pixels (224-896)")
	color := fs.Bool("color", false, "Apply L4 colormap to spectrogram")
	night := fs.Bool("night", false, "Only clip recordings made during solar night")
	day := fs.Bool("day", false, "Only clip recordings made during solar day")
	location := fs.String("location", "", "GPS coordinates and optional timezone")

	fs.Usage = printClipUsage
	_ = fs.Parse(args)

	if *certainty < -1 || *certainty > 100 {
		fmt.Fprintf(os.Stderr, "Error: --certainty must be between 0 and 100\n")
		os.Exit(1)
	}

	return clipFlags{
		file:      *file,
		folder:    *folder,
		output:    *output,
		prefix:    *prefix,
		filter:    *filter,
		species:   *species,
		size:      *size,
		certainty: *certainty,
		color:     *color,
		night:     *night,
		day:       *day,
		location:  *location,
	}
}

// validateClipFlags checks required flags and flag combinations
func validateClipFlags(f clipFlags) {
	missing := []string{}
	if f.file == "" && f.folder == "" {
		missing = append(missing, "--file or --folder")
	}
	if f.output == "" {
		missing = append(missing, "--output")
	}
	if f.prefix == "" {
		missing = append(missing, "--prefix")
	}
	if len(missing) > 0 {
		fmt.Fprintf(os.Stderr, "Error: missing required flags: %v\n\n", missing)
		printClipUsage()
		os.Exit(1)
	}
	if f.night && f.day {
		fmt.Fprintf(os.Stderr, "Error: --night and --day are mutually exclusive\n\n")
		printClipUsage()
		os.Exit(1)
	}
	if (f.night || f.day) && f.location == "" {
		fmt.Fprintf(os.Stderr, "Error: --night/--day requires --location\n\n")
		printClipUsage()
		os.Exit(1)
	}
}

// RunCallsClip handles the "calls clip" subcommand
//
// JSON output schema:
//
//	{
//	  "files_processed": int,       // .data files processed
//	  "segments_clipped": int,      // Segments that generated clips
//	  "night_skipped": int,         // Segments skipped (--night, omitted if 0)
//	  "day_skipped": int,           // Segments skipped (--day, omitted if 0)
//	  "output_files": [string],     // Paths to generated clip files (.wav/.png)
//	  "errors": [string]            // Error messages (omitted if empty)
//	}
func RunCallsClip(args []string) {
	f := parseClipArgs(args)
	validateClipFlags(f)

	// Build input
	input := tools.CallsClipInput{
		File:      f.file,
		Folder:    f.folder,
		Output:    f.output,
		Prefix:    f.prefix,
		Filter:    f.filter,
		Species:   f.species,
		Certainty: f.certainty,
		Size:      f.size,
		Color:     f.color,
		Night:     f.night,
		Day:       f.day,
		Location:  f.location,
	}

	// Execute
	result, err := tools.CallsClip(input)
	if err != nil {
		// Print partial result as JSON (may contain useful info)
		data, _ := json.Marshal(result)
		fmt.Println(string(data))
		os.Exit(1)
	}

	// Output JSON
	data, _ := json.Marshal(result)
	fmt.Println(string(data))
}