package utils

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
)

// ~/.skraak/config.json schema (reference):
//
//	{
//	  "classify": {
//	    "reviewer":  "string, required. Name stamped into .data file meta on any edit.",
//	    "color":     "bool, optional. Colored spectrograms in the TUI. Default false.",
//	    "sixel":     "bool, optional. Use sixel image protocol. Default false (Kitty).",
//	    "iterm":     "bool, optional. Use iTerm inline-image protocol. Default false.",
//	    "img_dims":  "int, optional. Spectrogram display size in pixels. 0 = default.",
//
//	    "bindings": {
//	      "<key>": "Species"              // e.g. "c": "comcha"
//	      "<key>": "Species+CallType"     // e.g. "1": "Kiwi+Duet"
//	      // <key> is a single character. Reserved: ",", ".", "0", " " (space).
//	      // Pressing <key> labels the current segment (certainty 100, or 0 for
//	      // "Don't Know"), saves, and advances.
//	    },
//
//	    "secondary_bindings": {
//	      "<primary-key>": {
//	        "<key>": "CallType"           // e.g. "a": "alarm"
//	        // <key> is a single character, same reserved-key rules as bindings.
//	        // Outer <primary-key> must also exist in "bindings".
//	      }
//	      // Optional. Invoked via Shift+<primary-key>: labels the species with
//	      // an empty calltype, does NOT advance, and waits for one follow-up
//	      // key looked up in this inner map. Match -> set calltype, save,
//	      // advance. Esc -> exit wait mode without advancing. Any other key ->
//	      // exit wait mode and handle the key normally.
//	      // Shift+<primary-key> on a primary without a secondary_bindings entry
//	      // falls back to normal primary behavior.
//	    }
//	  }
//	}
//
// Example:
//
//	{
//	  "classify": {
//	    "reviewer": "David",
//	    "color": true,
//	    "bindings": {
//	      "c": "comcha",
//	      "k": "kea1",
//	      "x": "Noise",
//	      "z": "Don't Know",
//	      "1": "Kiwi+Duet",
//	      "4": "Kiwi"
//	    },
//	    "secondary_bindings": {
//	      "c": { "a": "alarm", "s": "song", "n": "contact" }
//	    }
//	  }
//	}
//
// Config holds user-level defaults loaded from ~/.skraak/config.json.
// Per-subcommand sections live as named fields.
type Config struct {
	Classify ClassifyFileConfig `json:"classify"`
}

// ClassifyFileConfig holds defaults for `skraak calls classify`.
// Bindings maps a single-character key to "Species" or "Species+CallType".
type ClassifyFileConfig struct {
	Reviewer string            `json:"reviewer"`
	Color    bool              `json:"color"`
	Sixel    bool              `json:"sixel"`
	ITerm    bool              `json:"iterm"`
	ImgDims  int               `json:"img_dims"`
	Bindings map[string]string `json:"bindings"`
	// SecondaryBindings extends a primary binding with per-species calltype
	// choices. Outer key is the primary binding key; inner map is
	// single-char key -> calltype string. Invoked via Shift+primary-key.
	SecondaryBindings map[string]map[string]string `json:"secondary_bindings,omitempty"`
}

// ConfigPath returns the absolute path to ~/.skraak/config.json.
func ConfigPath() (string, error) {
	home, err := os.UserHomeDir()
	if err != nil {
		return "", fmt.Errorf("resolving home directory: %w", err)
	}
	return filepath.Join(home, ".skraak", "config.json"), nil
}

// LoadConfig reads ~/.skraak/config.json and returns the parsed config and the
// resolved path (useful for error messages).
func LoadConfig() (Config, string, error) {
	var cfg Config
	path, err := ConfigPath()
	if err != nil {
		return cfg, "", err
	}
	data, err := os.ReadFile(path)
	if err != nil {
		return cfg, path, fmt.Errorf("reading %s: %w", path, err)
	}
	if err := json.Unmarshal(data, &cfg); err != nil {
		return cfg, path, fmt.Errorf("parsing %s: %w", path, err)
	}
	return cfg, path, nil
}