"""WORAi root CLI."""

from __future__ import annotations

import logging
import os
import sys
import tomllib
from pathlib import Path


def _missing_runtime_dependency(name: str, install_hint: str) -> None:
    print(
        f"Missing runtime dependency '{name}'. {install_hint}",
        file=sys.stderr,
    )
    raise SystemExit(1)


try:
    import typer
except ModuleNotFoundError as exc:
    if exc.name == "typer":
        _missing_runtime_dependency(
            "typer",
            "Run `uv sync --extra dev` from the repo root, or install worai with `pipx install worai`.",
        )
    raise

try:
    from dotenv import find_dotenv, load_dotenv
except ModuleNotFoundError as exc:
    if exc.name == "dotenv":
        _missing_runtime_dependency(
            "python-dotenv",
            "Run `uv sync --extra dev` from the repo root, or install worai with `pipx install worai`.",
        )
    raise

from worai.config import resolve_config_path
from worai.errors import ConfigError
from worai.errors import WoraError
from worai.logging import setup_logging
from worai.update import check_for_update, command_to_string

app = typer.Typer(add_completion=True, no_args_is_help=True)


def _load_dotenv_defaults() -> None:
    """Load environment variables from .env without overriding real env vars."""
    dotenv_path = find_dotenv(usecwd=True)
    if dotenv_path:
        load_dotenv(dotenv_path=dotenv_path, override=False)


def _is_truthy(value: str | None) -> bool:
    if value is None:
        return False
    return value.strip().lower() in {"1", "true", "yes", "on"}


def _should_check_updates(ctx: typer.Context) -> bool:
    if os.environ.get("PYTEST_CURRENT_TEST"):
        return False
    if _is_truthy(os.environ.get("WORAI_DISABLE_UPDATE_CHECK")):
        return False
    args = set(sys.argv[1:])
    if "--help" in args or "--install-completion" in args or "--show-completion" in args:
        return False
    if (ctx.obj or {}).get("quiet"):
        return False
    return True


def _emit_update_notice(ctx: typer.Context) -> None:
    if not _should_check_updates(ctx):
        return
    from worai import __version__

    result = check_for_update(__version__, env=os.environ)
    if not result.update_available or not result.latest_version:
        return
    typer.secho(
        (
            f"Update available for worai: {result.current_version} -> {result.latest_version}. "
            f"Run `worai self update` or `{command_to_string(result.upgrade_command)}`."
        ),
        err=True,
        fg=typer.colors.YELLOW,
    )


def _resolve_log_level_from_config(config_path: Path, profile: str | None) -> str | None:
    try:
        data = tomllib.loads(config_path.read_text(encoding="utf-8"))
    except FileNotFoundError:
        return None
    except tomllib.TOMLDecodeError as exc:
        raise ConfigError(f"Invalid TOML config: {config_path}: {exc}") from exc

    global_value = data.get("log_level")
    profile_name = profile or os.environ.get("WORAI_PROFILE")
    profile_table = data.get("profile") or data.get("profiles") or {}
    profile_value = None
    if profile_name and isinstance(profile_table, dict):
        profile_value = (profile_table.get(profile_name) or {}).get("log_level")

    selected = profile_value if profile_value is not None else global_value
    if selected is None:
        return None
    if not isinstance(selected, str):
        raise ConfigError("log_level in config must be a string")
    normalized = selected.strip().lower()
    if normalized not in {"debug", "info", "warning", "error"}:
        raise ConfigError("log_level in config must be one of: debug, info, warning, error")
    return normalized


def _resolve_log_level(
    *,
    cli_value: str | None,
    config_path: Path,
    profile: str | None,
    env: dict[str, str] | None = None,
) -> str:
    if cli_value:
        return cli_value
    runtime_env = env if env is not None else os.environ
    env_value = runtime_env.get("WORAI_LOG_LEVEL")
    if env_value:
        return env_value
    config_value = _resolve_log_level_from_config(config_path, profile)
    if config_value:
        return config_value
    return "info"


@app.callback()
def main(
    ctx: typer.Context,
    config: str | None = typer.Option(None, "--config", help="Path to config TOML."),
    profile: str | None = typer.Option(None, "--profile", help="Config profile name."),
    log_level: str | None = typer.Option(None, "--log-level", help="Log level."),
    log_format: str = typer.Option("text", "--log-format", help="Log format: text or json."),
    quiet: bool = typer.Option(False, "--quiet", help="Only warnings and errors."),
) -> None:
    """WORAi command-line tools."""
    _load_dotenv_defaults()
    resolved_config_path = resolve_config_path(config, env=os.environ)
    resolved_log_level = _resolve_log_level(
        cli_value=log_level,
        config_path=resolved_config_path,
        profile=profile,
    )
    setup_logging(level=resolved_log_level, fmt=log_format, quiet=quiet)
    ctx.obj = {
        "config_path": resolved_config_path,
        "profile": profile,
        "log_level": resolved_log_level,
        "log_format": log_format,
        "quiet": quiet,
    }
    _emit_update_notice(ctx)


@app.command("version")
def version() -> None:
    """Show the CLI version."""
    from worai import __version__

    typer.echo(__version__)


def _install_commands() -> None:
    from worai.commands import (
        canonicalize_duplicate_pages,
        delete_entities_from_csv,
        dedupe,
        find_faq_page_wrong_type,
        find_missing_names,
        find_url_by_type,
        graph,
        google_search_console,
        link_groups,
        list_entities_outside_dataset,
        patch,
        self_update,
        seocheck,
        structured_data,
        upload_entities_from_turtle,
        validate,
        dil_import
    )
    from worai.seoreport import cli as seoreport_cli

    app.command("seocheck", help="Run SEO checks for sitemap URLs and URL lists.")(seocheck.run)
    app.add_typer(
        seoreport_cli.app,
        name="seoreport",
        help="Generate an SEO performance report.",
    )
    app.add_typer(
        google_search_console.app,
        name="google-search-console",
        help="Export Google Search Console data as CSV.",
    )
    app.add_typer(dedupe.app, name="dedupe", help="Deduplicate entities by schema:url.")
    app.add_typer(
        canonicalize_duplicate_pages.app,
        name="canonicalize-duplicate-pages",
        help="Select canonical targets for duplicate pages.",
    )
    app.add_typer(
        delete_entities_from_csv.app,
        name="delete-entities-from-csv",
        help="Delete entities listed in a CSV file.",
    )
    app.add_typer(
        find_faq_page_wrong_type.app,
        name="find-faq-page-wrong-type",
        help="Find and patch FAQPage typing issues.",
    )
    app.add_typer(
        find_missing_names.app,
        name="find-missing-names",
        help="Find entities missing schema:name in Turtle data.",
    )
    app.add_typer(
        find_url_by_type.app,
        name="find-url-by-type",
        help="List URLs by schema type from Turtle data.",
    )
    app.add_typer(
        graph.app,
        name="graph",
        help="Run graph workflows.",
    )
    app.add_typer(link_groups.app, name="link-groups", help="Build or apply internal link groups.")
    app.add_typer(patch.app, name="patch", help="Patch entities from RDF (Turtle or JSON-LD).")
    app.add_typer(self_update.app, name="self", help="Manage worai CLI updates.")
    app.add_typer(
        structured_data.app,
        name="structured-data",
        help="Generate structured data mappings or materialize RDF from YARRRML.",
    )
    app.add_typer(
        list_entities_outside_dataset.app,
        name="list-entities-outside-dataset",
        help="List entities outside the account dataset.",
    )
    app.add_typer(
        upload_entities_from_turtle.app,
        name="upload-entities-from-turtle",
        help="Upload Turtle entities with resume support.",
    )
    app.add_typer(
        validate.app,
        name="validate",
        help="Validate JSON-LD with SHACL shapes.",
    )
    app.add_typer(
        dil_import.app,
        name="dil-import",
        help="Import internal links into the KG.",
    )


_install_commands()


def run() -> None:
    try:
        app()
    except WoraError as exc:
        logging.getLogger("worai").error(str(exc))
        raise SystemExit(exc.exit_code) from exc


if __name__ == "__main__":
    run()
