package cmd

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

	"skraak/tools"
)

// runCallsClipLabels handles the "calls clip-labels" subcommand.
func runCallsClipLabels(args []string) {
	fs := flag.NewFlagSet("calls clip-labels", flag.ExitOnError)
	folder := fs.String("folder", "", "Folder containing .data files (required)")
	mapping := fs.String("mapping", "", "Path to mapping.json (required)")
	filter := fs.String("filter", "", "Restrict to a single filter name (default: all filters)")
	output := fs.String("output", "./clip_labels.csv", "Output CSV path")
	clipDuration := fs.Float64("clip-duration", 4.0, "Clip duration in seconds")
	clipOverlap := fs.Float64("clip-overlap", 0.5, "Clip overlap in seconds")
	minLabelOverlap := fs.Float64("min-label-overlap", 0.25, "Minimum overlap (s) for an annotation to label a clip")
	finalClip := fs.String("final-clip", "full", "Trailing-clip behaviour: full | remainder | extend | none")

	fs.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: skraak calls clip-labels [options]\n\n")
		fmt.Fprintf(os.Stderr, "Generate an OpenSoundScape clip_labels-format CSV from .data files.\n\n")
		fmt.Fprintf(os.Stderr, "Options:\n")
		fs.PrintDefaults()
		fmt.Fprintf(os.Stderr, "\nSegment policy:\n")
		fmt.Fprintf(os.Stderr, "  - Real species → contributes mapped class to overlapping clips.\n")
		fmt.Fprintf(os.Stderr, "  - Mapped to __NEGATIVE__ → clip emitted, all class columns False;\n")
		fmt.Fprintf(os.Stderr, "    overrides positives in the same clip.\n")
		fmt.Fprintf(os.Stderr, "  - Mapped to __IGNORE__ → segment contributes no labels to clips.\n")
		fmt.Fprintf(os.Stderr, "  - Gaps → clip emitted with all class columns False.\n")
		fmt.Fprintf(os.Stderr, "\nIf --output exists: append. Column-set mismatch → hard error.\n")
		fmt.Fprintf(os.Stderr, "Duplicate (file, start_time, end_time) row → hard error on first.\n")
		fmt.Fprintf(os.Stderr, "\nExamples:\n")
		fmt.Fprintf(os.Stderr, "  skraak calls clip-labels --folder ./recordings --mapping ./mapping.json\n")
		fmt.Fprintf(os.Stderr, "  skraak calls clip-labels --folder ./recordings --mapping ./mapping.json \\\n")
		fmt.Fprintf(os.Stderr, "      --filter opensoundscape-multi-1.0\n")
	}

	if err := fs.Parse(args); err != nil {
		os.Exit(1)
	}

	if *folder == "" {
		fmt.Fprintf(os.Stderr, "Error: --folder is required\n\n")
		fs.Usage()
		os.Exit(1)
	}
	if *mapping == "" {
		fmt.Fprintf(os.Stderr, "Error: --mapping is required\n\n")
		fs.Usage()
		os.Exit(1)
	}

	input := tools.CallsClipLabelsInput{
		Folder:          *folder,
		MappingPath:     *mapping,
		Filter:          *filter,
		OutputPath:      *output,
		ClipDuration:    *clipDuration,
		ClipOverlap:     *clipOverlap,
		MinLabelOverlap: *minLabelOverlap,
		FinalClip:       *finalClip,
	}

	fmt.Fprintf(os.Stderr, "Folder:    %s\n", *folder)
	fmt.Fprintf(os.Stderr, "Mapping:   %s\n", *mapping)
	fmt.Fprintf(os.Stderr, "Output:    %s\n", *output)
	fmt.Fprintf(os.Stderr, "Clip:      duration=%.3fs overlap=%.3fs final=%s min-label-overlap=%.3fs\n",
		*clipDuration, *clipOverlap, *finalClip, *minLabelOverlap)
	if *filter != "" {
		fmt.Fprintf(os.Stderr, "Filter:    %s\n", *filter)
	}

	out, err := tools.CallsClipLabels(input)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}

	fmt.Fprintf(os.Stderr, "\nResults\n")
	fmt.Fprintf(os.Stderr, "  .data files parsed:         %d\n", out.DataFilesParsed)
	fmt.Fprintf(os.Stderr, "  Segments ignored (__IGNORE__): %d\n", out.SegmentsIgnored)
	fmt.Fprintf(os.Stderr, "  Clips excluded (__IGNORE__):  %d\n", out.ClipsIgnored)
	fmt.Fprintf(os.Stderr, "  Clips emitted:              %d\n", out.RowsWritten)
	fmt.Fprintf(os.Stderr, "    negative (__NEGATIVE__):  %d\n", out.ClipsNegative)
	fmt.Fprintf(os.Stderr, "    all-False (gap):          %d\n", out.ClipsAllFalseGap)
	if out.AppendedToFile {
		fmt.Fprintf(os.Stderr, "  Appended to file:           yes (%d existing rows)\n", out.ExistingRowsFound)
	}
	fmt.Fprintf(os.Stderr, "\nPer-class True counts:\n")
	keys := make([]string, 0, len(out.PerClassTrueCount))
	for k := range out.PerClassTrueCount {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		fmt.Fprintf(os.Stderr, "  %-30s %d\n", k+":", out.PerClassTrueCount[k])
	}

	enc := json.NewEncoder(os.Stdout)
	enc.SetIndent("", "  ")
	if err := enc.Encode(out); err != nil {
		fmt.Fprintf(os.Stderr, "Error encoding output: %v\n", err)
		os.Exit(1)
	}
}