"""CLI commands for harvest-session-dbs."""

from __future__ import annotations

from pathlib import Path
from typing import Annotated

import typer
import yaml
from loguru import logger
from rich.table import Table

from harvest_session_dbs.cli.main import app, config_app, get_context
from harvest_session_dbs.config.models import (
    DEFAULT_HOSTS,
    DEFAULT_TOOLS,
    HarvestConfig,
)
from harvest_session_dbs.config.settings import load_config
from harvest_session_dbs.core.harvest import (
    get_current_date,
    harvest_from_host,
)
from harvest_session_dbs.core.tools import get_supported_tools, get_tool_info


@app.command()
def harvest(
    ctx: typer.Context,
    output_dir: Annotated[
        Path | None,
        typer.Option(
            "--output-dir",
            "-o",
            help="Directory to store harvested DB files.",
            envvar="SESSION_FIXTURES_DIR",
            show_default=True,
        ),
    ] = None,
    host: Annotated[
        list[str] | None,
        typer.Option(
            "--host",
            "-H",
            help="Host to harvest from (repeatable). Overrides config.",
        ),
    ] = None,
    tool: Annotated[
        list[str] | None,
        typer.Option(
            "--tool",
            "-T",
            help="Tool to harvest (repeatable). Overrides config.",
        ),
    ] = None,
    dry_run: Annotated[
        bool,
        typer.Option("--dry-run", help="Show what would be harvested without copying."),
    ] = False,
    dump_schema: Annotated[
        bool,
        typer.Option(
            "--dump-schema",
            help="Also dump the DB schema to a .schema.sql file alongside each fixture.",
        ),
    ] = False,
) -> None:
    """Harvest session DB files from configured hosts and tools."""
    app_ctx = get_context(ctx)
    cfg = load_config(app_ctx.config_path)

    out_dir = output_dir or cfg.output_dir
    hosts = host if host else cfg.hosts
    tools = tool if tool else cfg.tools

    if not hosts:
        logger.error("No hosts configured. Use --host or configure harvest-session-dbs.yaml.")
        raise typer.Exit(1)
    if not tools:
        logger.error("No tools configured. Use --tool or configure harvest-session-dbs.yaml.")
        raise typer.Exit(1)

    date_str = get_current_date()
    logger.info(f"Harvesting from {len(hosts)} hosts, {len(tools)} tools -> {out_dir}")
    logger.info(f"Date: {date_str}")

    if dry_run:
        logger.info("DRY RUN - no files will be copied")
    if dump_schema:
        logger.info("Schema dump enabled — .schema.sql files will be created alongside fixtures")

    out_dir.mkdir(parents=True, exist_ok=True)

    results: list[dict[str, str]] = []
    collected = 0
    failed = 0
    skipped = 0

    for h in hosts:
        for t in tools:
            if get_tool_info(t) is None:
                logger.warning(f"Unknown tool: {t}, skipping")
                skipped += 1
                continue
            r = harvest_from_host(h, t, out_dir, date_str, dry_run=dry_run, dump_schema=dump_schema)
            results.append(r)
            if r["status"] == "ok":
                collected += 1
            elif r["status"] == "failed":
                failed += 1

    # Summary table
    table = Table(title="Harvest Results")
    table.add_column("Tool", style="cyan")
    table.add_column("Host", style="green")
    table.add_column("Version", style="yellow")
    table.add_column("Filename")
    table.add_column("Status")

    for r in results:
        status_style = (
            "green" if r["status"] == "ok" else ("yellow" if r["status"] == "dry-run" else "red")
        )
        table.add_row(
            r["tool"],
            r["host"],
            r["version"],
            r["filename"],
            f"[{status_style}]{r['status']}[/]",
        )

    app_ctx.console.print(table)
    logger.info(f"Done: {collected} collected, {failed} failed, {skipped} skipped")

    if failed > 0 and collected == 0:
        raise typer.Exit(1)


@app.command()
def hosts(
    ctx: typer.Context,
) -> None:
    """List configured hosts."""
    app_ctx = get_context(ctx)
    cfg = load_config(app_ctx.config_path)
    if not cfg.hosts:
        print("No hosts configured.")
        return
    print("Configured hosts:")
    for h in cfg.hosts:
        print(f"  - {h}")


@app.command()
def tools(
    ctx: typer.Context,
) -> None:
    """List supported tools."""
    print("Supported tools:")
    for t in get_supported_tools():
        info = get_tool_info(t)
        if info:
            path, cmd = info
            print(f"  - {t}: {path} (version via: {' '.join(cmd)})")


@app.command(name="init")
def init_config(
    ctx: typer.Context,
    force: Annotated[
        bool,
        typer.Option("--force", help="Overwrite existing config."),
    ] = False,
) -> None:
    """Create a default config file."""
    app_ctx = get_context(ctx)
    config_path = app_ctx.config_path
    if config_path.exists() and not force:
        logger.error(f"Config already exists at {config_path}. Use --force to overwrite.")
        raise typer.Exit(1)
    default = HarvestConfig(
        hosts=list(DEFAULT_HOSTS),
        tools=list(DEFAULT_TOOLS),
    )
    data = default.model_dump(mode="json")
    config_path.parent.mkdir(parents=True, exist_ok=True)
    with config_path.open("w", encoding="utf-8") as f:
        yaml.dump(data, f, sort_keys=False, allow_unicode=True)
    print(f"Created config at {config_path}")


@app.command(name="list-fixtures")
def list_fixtures(
    ctx: typer.Context,
    output_dir: Annotated[
        Path | None,
        typer.Option(
            "--output-dir",
            "-o",
            help="Fixture directory to list.",
            envvar="SESSION_FIXTURES_DIR",
            show_default=True,
        ),
    ] = None,
) -> None:
    """List existing fixture DB files in the output directory."""
    from datetime import datetime

    app_ctx = get_context(ctx)
    cfg = load_config(app_ctx.config_path)
    out_dir = output_dir or cfg.output_dir

    if not out_dir.exists():
        print(f"Fixture directory does not exist: {out_dir}")
        return

    files = sorted(out_dir.glob("*.db"))
    if not files:
        print(f"No .db files found in {out_dir}")
        return

    table = Table(title=f"Fixtures in {out_dir}")
    table.add_column("Filename", style="cyan")
    table.add_column("Size", justify="right", style="green")
    table.add_column("Modified", style="dim")

    for f in files:
        size = f.stat().st_size
        if size > 1024 * 1024:
            size_str = f"{size / (1024 * 1024):.1f} MB"
        elif size > 1024:
            size_str = f"{size / 1024:.1f} KB"
        else:
            size_str = f"{size} B"
        mtime = datetime.fromtimestamp(f.stat().st_mtime).strftime("%Y-%m-%d %H:%M")
        table.add_row(f.name, size_str, mtime)

    app_ctx.console.print(table)


@config_app.command(name="path")
def config_path_cmd(
    ctx: typer.Context,
) -> None:
    """Show the config file path."""
    app_ctx = get_context(ctx)
    print(app_ctx.config_path)


@config_app.command(name="show")
def config_show(
    ctx: typer.Context,
) -> None:
    """Show the current configuration."""
    app_ctx = get_context(ctx)
    cfg = load_config(app_ctx.config_path)
    print(f"Config file:  {app_ctx.config_path}")
    print(f"Output dir:   {cfg.output_dir}")
    print(f"Hosts ({len(cfg.hosts)}):")
    for h in cfg.hosts:
        print(f"  - {h}")
    print(f"Tools ({len(cfg.tools)}):")
    for t in cfg.tools:
        print(f"  - {t}")
