package cmd

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

	"skraak/tools"
	"skraak/utils"
)

func printPushCertaintyUsage() {
	fmt.Fprintf(os.Stderr, "Usage: skraak calls push-certainty [options]\n\n")
	fmt.Fprintf(os.Stderr, "Promote certainty=90 segments to certainty=100 for a filtered set.\n")
	fmt.Fprintf(os.Stderr, "Filtering logic matches 'calls classify' exactly. Reviewer is set from config.\n\n")
	fmt.Fprintf(os.Stderr, "Options:\n")
	fmt.Fprintf(os.Stderr, "  --folder <path>       Path to folder containing .data files (required, or --file)\n")
	fmt.Fprintf(os.Stderr, "  --file <path>         Path to a single .data file (required, or --folder)\n")
	fmt.Fprintf(os.Stderr, "  --filter <name>       Scope to filter name (optional)\n")
	fmt.Fprintf(os.Stderr, "  --species <name>      Scope to species, optionally with calltype (e.g. Kiwi, Kiwi+Duet)\n")
	fmt.Fprintf(os.Stderr, "  --night               Only act on solar-night recordings (requires --location)\n")
	fmt.Fprintf(os.Stderr, "  --day                 Only act on solar-day recordings (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, "\nExamples:\n")
	fmt.Fprintf(os.Stderr, "  skraak calls push-certainty --folder ./data --species Kiwi\n")
	fmt.Fprintf(os.Stderr, "  skraak calls push-certainty --folder ./data --species Kiwi --night --location \"-45.5,167.4\"\n")
}

// pushCertaintyFlags holds the parsed CLI flags for push-certainty
type pushCertaintyFlags struct {
	folder   string
	file     string
	filter   string
	species  string
	night    bool
	day      bool
	location string
}

// parsePushCertaintyArgs parses CLI arguments into flags
func parsePushCertaintyArgs(args []string) pushCertaintyFlags {
	var f pushCertaintyFlags
	i := 0
	for i < len(args) {
		arg := args[i]
		switch arg {
		case "--folder":
			f.folder = requireValue(arg, args, &i)
		case "--file":
			f.file = requireValue(arg, args, &i)
		case "--filter":
			f.filter = requireValue(arg, args, &i)
		case "--species":
			f.species = requireValue(arg, args, &i)
		case "--night":
			f.night = true
			i++
		case "--day":
			f.day = true
			i++
		case "--location":
			if f.location != "" {
				fmt.Fprintf(os.Stderr, "Error: --location can only be specified once\n")
				os.Exit(1)
			}
			f.location = requireValue(arg, args, &i)
		case "--help", "-h":
			printPushCertaintyUsage()
			os.Exit(0)
		default:
			fmt.Fprintf(os.Stderr, "Error: unknown flag: %s\n\n", arg)
			printPushCertaintyUsage()
			os.Exit(1)
		}
	}
	return f
}

// requireValue returns the next argument after a flag, or exits with an error
func requireValue(flag string, args []string, i *int) string {
	if *i+1 >= len(args) {
		fmt.Fprintf(os.Stderr, "Error: %s requires a value\n", flag)
		os.Exit(1)
	}
	v := args[*i+1]
	*i += 2
	return v
}

// validatePushCertaintyFlags checks flag combinations and exits on error
func validatePushCertaintyFlags(f pushCertaintyFlags) {
	if f.folder == "" && f.file == "" {
		fmt.Fprintf(os.Stderr, "Error: missing required flag: --folder or --file\n\n")
		printPushCertaintyUsage()
		os.Exit(1)
	}
	if f.night && f.day {
		fmt.Fprintf(os.Stderr, "Error: --night and --day are mutually exclusive\n\n")
		printPushCertaintyUsage()
		os.Exit(1)
	}
	if (f.night || f.day) && f.location == "" {
		fmt.Fprintf(os.Stderr, "Error: --night/--day requires --location\n\n")
		printPushCertaintyUsage()
		os.Exit(1)
	}
}

// runCallsPushCertainty promotes certainty=90 segments to certainty=100 for a filtered set.
//
// JSON output schema:
//
//	{
//	  "segments_updated": int,      // Number of segments promoted from 90→100
//	  "files_updated": int,         // Number of .data files modified
//	  "time_filtered_count": int    // Files skipped by --night/--day filter
//	}
func runCallsPushCertainty(args []string) {
	f := parsePushCertaintyArgs(args)
	validatePushCertaintyFlags(f)

	cfg, cfgPath, err := utils.LoadConfig()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		fmt.Fprintf(os.Stderr, "Create %s with a \"classify\" section; run `skraak calls classify --help` for an example.\n", cfgPath)
		os.Exit(1)
	}
	if cfg.Classify.Reviewer == "" {
		fmt.Fprintf(os.Stderr, "Error: %s is missing \"classify.reviewer\"\n", cfgPath)
		os.Exit(1)
	}

	speciesName, callType := utils.ParseSpeciesCallType(f.species)

	var lat, lng float64
	var timezone string
	if f.location != "" {
		var err error
		lat, lng, timezone, err = utils.ParseLocation(f.location)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error: %v\n", err)
			os.Exit(1)
		}
	}

	config := tools.PushCertaintyConfig{
		Folder:   f.folder,
		File:     f.file,
		Filter:   f.filter,
		Species:  speciesName,
		CallType: callType,
		Night:    f.night,
		Day:      f.day,
		Lat:      lat,
		Lng:      lng,
		Timezone: timezone,
		Reviewer: cfg.Classify.Reviewer,
	}

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

	if result.TimeFilteredCount > 0 {
		label := "daytime"
		if config.Day {
			label = "nighttime"
		}
		fmt.Fprintf(os.Stderr, "Skipped %d %s files\n", result.TimeFilteredCount, label)
	}
	fmt.Fprintf(os.Stderr, "Updated %d segments across %d files\n",
		result.SegmentsUpdated, result.FilesUpdated)

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