"""Interactive wizard for the `rai init` command.

Three entry paths:
  1. Existing raiconfig.yaml / raiconfig.yml  → validate and confirm all is good
  2. raiconfig.toml found                      → offer migration or create template
  3. No config found                           → create raiconfig.yaml from template
"""

from __future__ import annotations

import sys
from pathlib import Path
from typing import TYPE_CHECKING, Any

import click
import rich

if TYPE_CHECKING:
    from relationalai.config.config import Config

# ── Constants ────────────────────────────────────────────────────────────────
RAICONFIG_YAML = "raiconfig.yaml"
RAICONFIG_YML = "raiconfig.yml"

_DIVIDER = "[dim]" + "─" * 52 + "[/dim]"


# ── Public entry point ───────────────────────────────────────────────────────

def run_init_wizard(*, migrate: bool = False) -> None:
    """Entry point called from cli.py init command."""
    rich.print(f"\n{_DIVIDER}")
    rich.print("[bold]Welcome to [green]RelationalAI[/green]![/bold]")
    rich.print("[dim]Setting up your raiconfig.yaml.[/dim]")
    rich.print(_DIVIDER)

    if migrate:
        from relationalai.config.external.utils import find_raiconfig_toml_file
        toml_path = find_raiconfig_toml_file()
        if toml_path is not None:
            _migration_path(Path(toml_path))
        else:
            rich.print("\n[yellow]No raiconfig.toml found.[/yellow]")
            rich.print("[dim]Run [bold]rai init[/bold] to create a raiconfig.yaml from template or validate your existing config.[/dim]")
        return

    yaml_path = _find_existing_yaml()
    if yaml_path is not None:
        _existing_yaml_path(yaml_path)
        return

    from relationalai.config.external.utils import find_raiconfig_toml_file
    toml_path = find_raiconfig_toml_file()

    if toml_path is not None:
        rich.print(f"\n[bold]Found existing config:[/bold] [cyan]{toml_path}[/cyan]")
        rich.print("  [bold]1.[/bold] Migrate your raiconfig.toml to raiconfig.yaml")
        rich.print("  [bold]2.[/bold] Create a fresh raiconfig.yaml from template")
        idx = click.prompt("Choice", type=click.IntRange(1, 2), default=1)
        if idx == 1:
            _migration_path(Path(toml_path))
        else:
            _create_template()
    else:
        _create_template()


# ── Path 1: Existing YAML ────────────────────────────────────────────────────

def _find_existing_yaml() -> Path | None:
    """Return path to raiconfig.yaml or raiconfig.yml searching upward from cwd,
    matching the same discovery behaviour as create_config()."""
    from confocal import find_upwards
    for name in (RAICONFIG_YAML, RAICONFIG_YML):
        found = find_upwards(Path(name))
        if found:
            return found
    return None


_TEMPLATE_PLACEHOLDERS = {"myorg-myaccount", "you@example.com", "your_password"}



def run_explain(config: Config, verbose: bool = False) -> None:
    """Print config explanation — file path is shown by config.explain() itself."""
    config.explain(verbose=verbose)


def _has_template_values(yaml_path: Path) -> bool:
    """Return True if the file still contains any known template placeholder values."""
    content = yaml_path.read_text(encoding="utf-8")
    return any(placeholder in content for placeholder in _TEMPLATE_PLACEHOLDERS)


def _existing_yaml_path(yaml_path: Path) -> None:
    """Validate existing raiconfig.yaml and report status."""
    try:
        from relationalai.config import create_config
        run_explain(create_config())
        rich.print(f"\n{_DIVIDER}")
        if _has_template_values(yaml_path):
            rich.print("[yellow]⚠ Your config still contains template placeholder values.[/yellow]")
            rich.print(f"[dim]Edit [bold]{yaml_path}[/bold] and replace the example values with your own, then run [bold]rai init[/bold] again.[/dim]")
        else:
            rich.print("[green]✓ You're all set![/green] Your config is valid and ready to use.")
        rich.print(f"{_DIVIDER}\n")
    except Exception as e:
        rich.print(f"\n[yellow]⚠ Config has issues:[/yellow]\n{e}")
        rich.print("\n[dim]Edit your raiconfig.yaml to fix the issues above.[/dim]")


# ── Path 2: Migration from raiconfig.toml ───────────────────────────────────

def _warn_dropped_fields(toml_data: dict[str, Any], profiles_to_migrate: list[str]) -> None:
    """Print actionable warnings for TOML fields dropped during migration (CLI-managed only)."""
    hints: list[str] = []

    def _check(source: dict[str, Any], reasoner_name: str | None, type_key: str = "logic") -> None:
        name_part = f" --name {reasoner_name}" if reasoner_name else ""
        if "auto_suspend_mins" in source and source["auto_suspend_mins"] is not None:
            value = source["auto_suspend_mins"]
            hints.append(
                f"  rai reasoners:alter --type {type_key}{name_part} --auto-suspend-mins {value}"
            )
        if "await_storage_vacuum" in source and source["await_storage_vacuum"] is not None:
            value = source["await_storage_vacuum"]
            flag = "--await-storage-vacuum" if value else "--no-await-storage-vacuum"
            hints.append(
                f"  rai reasoners:create --type {type_key}{name_part} {flag}"
                f"  [dim](--await-storage-vacuum = true, --no-await-storage-vacuum = false)[/dim]"
            )

    # Check top-level TOML fields
    engine_name = toml_data.get("engine")
    _check(toml_data, engine_name)

    # Check per-profile fields
    for profile_name in profiles_to_migrate:
        profile_raw = toml_data.get("profile", {}).get(profile_name, {})
        engine_name = profile_raw.get("engine")
        _check(profile_raw, engine_name)

    if hints:
        rich.print(
            "\n[yellow]⚠ The following fields were dropped during migration "
            "and must now be managed via the CLI:[/yellow]"
        )
        for hint in hints:
            rich.print(hint)


def _migration_path(toml_path: Path) -> None:
    """Convert raiconfig.toml → raiconfig.yaml preserving top-level vs profile structure."""
    try:
        import tomllib  # Python 3.11+
    except ImportError:
        try:
            import tomli as tomllib  # type: ignore[no-redef]
        except ImportError:
            rich.print(
                "[red]✗ TOML parser not available.[/red] "
                "Requires Python 3.11+ or the 'tomli' package."
            )
            sys.exit(1)

    with open(toml_path, "rb") as f:
        toml_data = tomllib.load(f)

    from relationalai.config.external.raiconfig_converter import map_fields_to_nested_structure, FIELD_MAPPINGS, CONNECTION_FIELDS
    from relationalai.config.external.raiconfig_models import RAIConfigFile, RAIConfigSnowflakeProfile, RAIConfigLocalProfile

    config_file = RAIConfigFile(**toml_data)
    profiles = config_file.profile
    profiles_to_migrate: list[str] = list(profiles.keys())

    if profiles_to_migrate:
        rich.print(f"\n[dim]Migrating {len(profiles_to_migrate)} profile(s): {', '.join(profiles_to_migrate)}[/dim]")

    active_profile = toml_data.get("active_profile") or (profiles_to_migrate[0] if profiles_to_migrate else "dev")

    # Top-level TOML fields → YAML top level (only explicitly set fields, not Pydantic defaults)
    explicitly_set = config_file.model_fields_set - {"profile", "active_profile"}
    toplevel_raw = config_file.model_dump(include=explicitly_set, exclude_none=True)
    yaml_data: dict[str, Any] = {
        "active_profile": active_profile,
        **map_fields_to_nested_structure(toplevel_raw),
        "profile": {},
    }

    out_path = Path(RAICONFIG_YAML)
    failed: list[str] = []
    _config_field_keys = set(FIELD_MAPPINGS.keys()) - CONNECTION_FIELDS

    for profile_name in profiles_to_migrate:
        profile_raw = profiles.get(profile_name, {})
        platform = profile_raw.get("platform", "snowflake")
        if platform not in ("snowflake", "local"):
            rich.print(f"  [yellow]⚠ Skipped '{profile_name}'[/yellow] [dim](platform '{platform}' is not supported in raiconfig.yaml)[/dim]")
            failed.append(profile_name)
            continue
        try:
            if platform == "local":
                profile_model = RAIConfigLocalProfile(**profile_raw)
                connection = profile_model.convert()
                conn_name = "local"
            else:
                profile_model = RAIConfigSnowflakeProfile(**profile_raw)
                connection = profile_model.convert()
                conn_name = "snowflake"
        except Exception as e:
            rich.print(f"\n[red]✗ Migration failed for '{profile_name}':[/red] {e}")
            failed.append(profile_name)
            continue

        # Profile-specific config overrides → go into the profile block as overrides
        profile_overrides_raw = {k: v for k, v in profile_raw.items() if k in _config_field_keys}
        profile_block: dict[str, Any] = {
            "default_connection": conn_name,
            "connections": {conn_name: connection},
        }
        if profile_overrides_raw:
            profile_block.update(map_fields_to_nested_structure(profile_overrides_raw))

        yaml_data["profile"][profile_name] = profile_block
        rich.print(f"  [green]✓[/green] [bold]{profile_name}[/bold] [dim](connection: {conn_name})[/dim]")

    if not yaml_data["profile"]:
        rich.print("\n[yellow]⚠ No profiles could be migrated.[/yellow]")
        if click.confirm("Create a fresh raiconfig.yaml from template instead?", default=True):
            _create_template()
        return

    _write_yaml(yaml_data, out_path)

    rich.print(f"\n{_DIVIDER}")
    rich.print(f"[green]✓ Migrated[/green] [cyan]{toml_path}[/cyan] → [cyan]{out_path}[/cyan]")
    if failed:
        rich.print(f"[yellow]⚠ Skipped profiles (errors above):[/yellow] {', '.join(failed)}")

    # Warn about fields dropped during migration that must now be managed via CLI.
    _warn_dropped_fields(toml_data, profiles_to_migrate)

    rich.print(f"\n[dim]Tip: Review {out_path}, then remove {toml_path} when ready.[/dim]")
    rich.print(f"{_DIVIDER}\n")


# ── Path 3: Create template ───────────────────────────────────────────────────

def _create_template() -> None:
    """Write raiconfig.yaml from the commented template."""
    from .template_config import CONFIG_TEMPLATE

    out_path = Path(RAICONFIG_YAML)
    out_path.write_text(CONFIG_TEMPLATE, encoding="utf-8")

    rich.print(f"\n{_DIVIDER}")
    rich.print(f"[green]✓ Created [bold]{out_path}[/bold][/green]")
    rich.print("[dim]Open it and fill in your connection details.[/dim]")
    rich.print(f"{_DIVIDER}\n")


# ── YAML serialization ───────────────────────────────────────────────────────

def _write_yaml(config_dict: dict, path: Path) -> None:
    """Serialize config dict to YAML with clean formatting."""
    import yaml

    content = yaml.dump(
        config_dict,
        default_flow_style=False,
        allow_unicode=True,
        sort_keys=False,
        indent=2,
    )
    content = _add_block_spacing(content)
    path.write_text(content, encoding="utf-8")


def _add_block_spacing(content: str) -> str:
    """Insert blank lines between sibling entries inside profile and connections blocks."""
    SPACED_KEYS = {"profile", "connections"}
    lines = content.splitlines()
    result: list[str] = []
    # Maps entry_indent → True (waiting for first entry) / False (first seen)
    spaced_blocks: dict[int, bool] = {}

    for line in lines:
        stripped = line.lstrip()
        if not stripped:
            result.append(line)
            continue

        current_indent = len(line) - len(stripped)

        # Pop blocks that are deeper than the current indent (we've left them)
        spaced_blocks = {k: v for k, v in spaced_blocks.items() if k <= current_indent}

        # If this line opens a tracked block (e.g. "profile:" or "connections:"),
        # register its child indent so siblings get blank lines between them.
        key = stripped.split(":")[0]
        if key in SPACED_KEYS and stripped == f"{key}:":
            spaced_blocks[current_indent + 2] = True

        # If we're at a tracked indent, insert a blank line before every sibling
        # except the first.
        if current_indent in spaced_blocks:
            if not spaced_blocks[current_indent]:
                result.append("")
            spaced_blocks[current_indent] = False

        result.append(line)

    return "\n".join(result) + "\n"


# ── Helpers ──────────────────────────────────────────────────────────────────

def _is_interactive() -> bool:
    """Return True when stdin is a TTY (interactive session)."""
    try:
        return bool(getattr(sys.stdin, "isatty", lambda: False)())
    except Exception:
        return False
