"""Entry point and custom argument parser for tacoshop."""

from __future__ import annotations

import sys
from dataclasses import dataclass, field

from tacoshop import __version__
from tacoshop.config import Config, ConfigError, FlagVar, load_config


SUBCOMMANDS = frozenset({"trace", "dumpenv", "init", "help", "print"})
BUILTIN_FLAGS = {
    "--help": "help",
    "-h": "help",
    "--verbose": "verbose",
    "-v": "verbose",
    "--dry-run": "dry_run",
    "--version": "version",
}


@dataclass
class ParseResult:
    help: bool = False
    verbose: bool = False
    dry_run: bool = False
    version: bool = False
    subcommand: str | None = None
    subcommand_args: list[str] = field(default_factory=list)
    command: list[str] = field(default_factory=list)
    activated_flags: dict[str, str] = field(default_factory=dict)  # env_name → value


def parse_args(argv: list[str], config: Config) -> ParseResult:
    """Parse argv using left-to-right sequential scanning.

    Algorithm:
    1. '--' → everything after is the command
    2. Known subcommand as first positional → subcommand mode
    3. Built-in flag → record it
    4. Config-defined flag → consume value if needed
    5. Anything else → start of command, stop parsing
    """
    result = ParseResult()
    i = 0
    first_positional = True

    while i < len(argv):
        token = argv[i]

        # Explicit separator: everything after is the command
        if token == "--":
            result.command = list(argv[i + 1 :])
            break

        # Built-in flags
        if token in BUILTIN_FLAGS:
            setattr(result, BUILTIN_FLAGS[token], True)
            i += 1
            continue

        # Config-defined flags
        if token in config.flag_lookup:
            fv: FlagVar = config.flag_lookup[token]
            if fv.value is not None:
                # Preset value: just activate
                result.activated_flags[fv.name] = fv.value
            else:
                # Value-required: consume next token
                i += 1
                if i >= len(argv):
                    print(
                        f"tacoshop: flag '{token}' requires a value",
                        file=sys.stderr,
                    )
                    sys.exit(2)
                result.activated_flags[fv.name] = argv[i]
            i += 1
            continue

        # Subcommand detection (only at first positional)
        if first_positional and token in SUBCOMMANDS:
            result.subcommand = token
            result.subcommand_args = list(argv[i + 1 :])
            break

        # Anything else starts the command
        result.command = list(argv[i:])
        break

    # Track that we've seen a non-flag token for subcommand detection
    # (This is handled by 'first_positional' staying True until we break)

    return result


def print_help(config: Config) -> None:
    """Print help message to stderr."""
    lines = [
        f"tacoshop {__version__} - run commands with configured environment variables",
        "",
        "Usage: tacoshop [FLAGS...] COMMAND [ARGS...]",
        "       tacoshop trace",
        "       tacoshop dumpenv [-o FILE]",
        "       tacoshop print COMMAND [ARGS...]",
        "       tacoshop init",
        "",
        "Built-in flags:",
        "  --help, -h       Show this help message",
        "  --verbose, -v    Print each env var before running",
        "  --dry-run        Show what would run without executing",
        "  --version        Show version",
    ]

    if config.flag_vars:
        lines.append("")
        lines.append("Config-defined flags:")
        for fv in sorted(config.flag_vars.values(), key=lambda f: f.flag):
            if fv.value is not None:
                flag_str = f"  {fv.flag}"
            else:
                flag_str = f"  {fv.flag} VALUE"
            desc = f"  {fv.description}" if fv.description else ""
            env_hint = f" → {fv.name}"
            append_hint = " (append)" if fv.append else " (prepend)" if fv.prepend else ""
            lines.append(f"{flag_str:<20}{desc}{env_hint}{append_hint}")

    if config.loaded_files:
        lines.append("")
        lines.append("Loaded config files:")
        for f in config.loaded_files:
            lines.append(f"  {f}")

    print("\n".join(lines), file=sys.stderr)


def main(argv: list[str] | None = None) -> None:
    """Main entry point."""
    if argv is None:
        argv = sys.argv[1:]

    try:
        config = load_config()
    except ConfigError as e:
        print(f"tacoshop: config error: {e}", file=sys.stderr)
        sys.exit(1)

    result = parse_args(argv, config)

    if result.version:
        print(f"tacoshop {__version__}", file=sys.stderr)
        sys.exit(0)

    if result.help:
        print_help(config)
        sys.exit(0)

    if result.subcommand == "help":
        print_help(config)
        sys.exit(0)

    if result.subcommand is not None:
        from tacoshop.commands import run_subcommand

        run_subcommand(result.subcommand, result.subcommand_args, config, result)
        return

    if not result.command:
        print_help(config)
        sys.exit(0)

    from tacoshop.runner import run_command

    run_command(result.command, config, result)


if __name__ == "__main__":
    main()
