"""tyta config subcommands: show, set."""

from __future__ import annotations

import sys
from typing import Annotated

import typer

from tyta.cli import render
from tyta.core import config as core_config
from tyta.core import envelope as env

app = typer.Typer(
    name="config",
    help="Manage tyta configuration.",
    no_args_is_help=True,
)


def _get_state() -> dict:
    from tyta.cli.main import _get_state as _gs

    return _gs()


def _get_config_path_override() -> str | None:
    return _get_state().get("config_file")


def _is_json_mode() -> bool:
    return _get_state().get("json", False)


def _load_config() -> dict:
    from tyta.core.config import get_config_path, load_config

    try:
        return load_config(get_config_path(_get_config_path_override()))
    except Exception:  # noqa: BLE001
        return {}


def _emit_and_exit(data: dict, exit_code: int = 0, command: str = "") -> None:
    """Render envelope (human or JSON) and exit."""
    json_mode = _is_json_mode()
    if exit_code != 0:
        render.render_error(data, json_mode)
    else:
        render.render_output(data, json_mode, command, config=_load_config())
    sys.exit(exit_code)


@app.command("show")
def config_show() -> None:
    """Print all config keys and their current values."""
    config_path = core_config.get_config_path(_get_config_path_override())

    try:
        config = core_config.load_config(config_path)
    except Exception as exc:  # noqa: BLE001
        _emit_and_exit(env.error("invalid_config", str(exc)), exit_code=1)
        return

    # Resolve effective values (fill in defaults for missing fields)
    effective = {
        "default_vin": config.get("default_vin", None),
        "date_format": config.get("date_format", core_config.DEFAULT_DATE_FORMAT),
        "distance_unit": config.get("distance_unit", core_config.DEFAULT_DISTANCE_UNIT),
    }
    _emit_and_exit(env.ok({"config": effective}), command="config show")


@app.command("set")
def config_set(
    key: Annotated[str, typer.Argument(help="Config key to set.")],
    value: Annotated[str, typer.Argument(help="Value to set.")],
) -> None:
    """Set a config key to the given value."""
    config_path = core_config.get_config_path(_get_config_path_override())

    # Validate key and value
    if key == "date_format":
        if value not in core_config.ACCEPTED_DATE_FORMATS:
            accepted = ", ".join(sorted(core_config.ACCEPTED_DATE_FORMATS))
            _emit_and_exit(
                env.error(
                    "invalid_input",
                    f"Invalid value '{value}' for date_format. Accepted: {accepted}.",
                ),
                exit_code=1,
            )
            return
    elif key == "distance_unit":
        if value not in core_config.ACCEPTED_DISTANCE_UNITS:
            accepted = ", ".join(sorted(core_config.ACCEPTED_DISTANCE_UNITS))
            _emit_and_exit(
                env.error(
                    "invalid_input",
                    f"Invalid value '{value}' for distance_unit. Accepted: {accepted}.",
                ),
                exit_code=1,
            )
            return
    elif key == "default_vin":
        # Any string is accepted for default_vin
        pass
    else:
        _emit_and_exit(
            env.error(
                "invalid_input",
                f"Unknown config key '{key}'. Accepted keys: date_format, distance_unit, default_vin.",
            ),
            exit_code=1,
        )
        return

    try:
        config = core_config.load_config(config_path)
    except Exception as exc:  # noqa: BLE001
        _emit_and_exit(env.error("invalid_config", str(exc)), exit_code=1)
        return

    config[key] = value
    core_config.save_config(config, config_path)

    _emit_and_exit(
        env.ok({"key": key, "value": value, "message": f"Set {key} = {value}"}),
        command="config set",
    )
