"""Initialize gjalla in a repository."""

import json
import os
from pathlib import Path

import click
import yaml
from rich.prompt import Prompt, Confirm

from gjalla_precommit.display.output import console, success, error, warning, info, panel
from gjalla_precommit.tools.git_tools import is_git_repo

from ._api import (
    verify_api_key,
    discover_or_select_project,
    _make_api_headers,
)
from ._shared import load_local_config, save_local_config, migrate_gjalla_file_to_dir, ensure_gitignore

# API timeout in seconds
API_TIMEOUT = 30.0


def load_global_config() -> dict:
    """Load global gjalla config from ~/.gjalla/config.yaml."""
    from ..config.settings import get_config_file

    config_path = get_config_file()
    if not config_path.exists():
        return {
            "api_key": None,
            "api_url": "https://gjalla.io",
            "projects": {},
        }

    with open(config_path) as f:
        return yaml.safe_load(f) or {}


def save_global_config(config: dict) -> None:
    """Save global gjalla config to ~/.gjalla/config.yaml."""
    from ..config.settings import get_config_dir, get_config_file

    gjalla_dir = get_config_dir()
    config_path = get_config_file()
    gjalla_dir.mkdir(parents=True, exist_ok=True)
    with open(config_path, "w") as f:
        yaml.dump(config, f, default_flow_style=False)


@click.command()
@click.option(
    "--api-key",
    envvar="GJALLA_API_KEY",
    help="API key for gjalla cloud. Can also be set via GJALLA_API_KEY env var.",
)
@click.option(
    "--project-id",
    type=int,
    help="Project ID. If not provided, will be auto-discovered from git remote.",
)
@click.option(
    "--yes", "-y",
    is_flag=True,
    help="Accept all defaults without prompting.",
)
def init(
    api_key: str | None,
    project_id: int | None,
    yes: bool = False,
) -> None:
    """Initialize gjalla in the current repository.

    This command sets up gjalla for your repository by:

    \b
    1. Checking git repository
    2. Configuring your API key (optional — skip for local-only usage)
    3. Verifying API key
    4. Selecting your project from Gjalla
    5. Creating .gjalla project config
    6. Updating .gitignore
    7. Installing commit attestation guardrails
    8. Installing MCP server for Claude Code

    Run without --api-key for local-only mode. Use 'gjalla connect' later to link a project.
    """
    repo_path = Path.cwd()

    from ..display.output import bridge_banner
    bridge_banner()
    panel("gjalla Initialization", title="gjalla init")
    console.print()

    # Step 1: Verify we're in a git repo
    info("Step 1/8: Checking git repository...")
    if not is_git_repo(repo_path):
        error("Not a git repository. Please run 'gjalla init' from a git repository.")
        raise SystemExit(1)
    success("Git repository detected")
    console.print()

    # Load existing config
    config = load_global_config()
    api_url = os.environ.get("GJALLA_API_URL") or config.get("api_url", "https://gjalla.io")

    if api_url != "https://gjalla.io":
        info(f"Using API URL: {api_url}")

    # Determine if we have an API key available
    has_api_key = False
    use_remote = False
    local_arch_path = None
    local_rules_path = None
    key_source = None  # "explicit", "config", or "prompt"

    if api_key or project_id:
        # --api-key or --project-id flags: skip branching prompt, go straight to remote
        use_remote = True
        if api_key:
            has_api_key = True
            key_source = "explicit"
            info("Step 2/8: Using API key from command line or environment")
        elif config.get("api_key"):
            api_key = config["api_key"]
            has_api_key = True
            key_source = "config"
            info("Step 2/8: Using existing API key from config")
    elif config.get("api_key"):
        api_key = config["api_key"]
        has_api_key = True
        key_source = "config"
        use_remote = True
        info("Step 2/8: Using existing API key from config")
    else:
        info("Step 2/8: Mode selection...")
        if yes:
            # -y with no API key → local-only flow
            info("No API key provided — setting up local-only mode")
        else:
            use_remote = Confirm.ask(
                "[bold]Are you connecting to a remote gjalla project?[/bold]",
                default=False,
            )
            if use_remote:
                api_key = Prompt.ask(
                    "[bold]Enter your gjalla API key[/bold] (get one at https://gjalla.io/settings/api)",
                    default="",
                    password=True,
                )
                if api_key:
                    has_api_key = True
                    key_source = "prompt"
                else:
                    error("API key is required for remote mode.")
                    raise SystemExit(1)
            else:
                # Local-only flow: prompt for arch and rules paths separately
                local_arch_path = Prompt.ask(
                    "[bold]Path to your architecture docs[/bold] (file or folder, blank to skip)",
                    default="",
                )
                if local_arch_path:
                    arch_p = Path(local_arch_path).expanduser().resolve()
                    if not arch_p.exists():
                        error(f"Path does not exist: {arch_p}")
                        raise SystemExit(1)
                    local_arch_path = str(arch_p)
                    success(f"Architecture docs: {local_arch_path}")
                else:
                    local_arch_path = None
                    info("  Skipped architecture docs. Add later with [bold]gjalla setup[/bold].")

                local_rules_path = Prompt.ask(
                    "[bold]Path to your rules/constraints docs[/bold] (file or folder, blank to skip)",
                    default="",
                )
                if local_rules_path:
                    rules_p = Path(local_rules_path).expanduser().resolve()
                    if not rules_p.exists():
                        error(f"Path does not exist: {rules_p}")
                        raise SystemExit(1)
                    local_rules_path = str(rules_p)
                    success(f"Rules docs: {local_rules_path}")
                else:
                    local_rules_path = None
                    info("  Skipped rules docs. Add later with [bold]gjalla setup[/bold].")

    project_info = None

    if has_api_key:
        success("API key configured")
        console.print()

        # Step 3: Verify API key
        info("Step 3/8: Verifying API key...")
        key_ok, key_detail = verify_api_key(api_key, api_url)
        if not key_ok and key_source == "config":
            # Try local sources as fallback, in order:
            # 1. Literal api_key from .gjalla/config.json
            # 2. api_key_env from .gjalla/config.json (env var reference)
            # 3. GJALLA_API_KEY from .mcp.json gjalla server entry
            local_config = load_local_config(repo_path) or None

            # Source 1: literal api_key
            if local_config:
                local_api_key = local_config.get("api_key")
                if local_api_key and local_api_key != api_key:
                    info("  Global API key failed, trying local .gjalla/config.yaml...")
                    local_api_url = local_config.get("api_url", api_url)
                    key_ok, key_detail = verify_api_key(local_api_key, local_api_url)
                    if key_ok:
                        api_key = local_api_key
                        api_url = local_api_url
                        key_source = "local_config"

            # Source 2: api_key_env (env var reference)
            if not key_ok and local_config:
                env_var_name = local_config.get("api_key_env", "")
                env_key = os.environ.get(env_var_name) if env_var_name else None
                if env_key and env_key != api_key:
                    info(f"  Trying {env_var_name} from environment...")
                    local_api_url = local_config.get("api_url", api_url)
                    key_ok, key_detail = verify_api_key(env_key, local_api_url)
                    if key_ok:
                        api_key = env_key
                        api_url = local_api_url
                        key_source = "local_config_env"

            # Source 3: .mcp.json gjalla server entry
            if not key_ok:
                try:
                    from .mcp import find_mcp_config
                    mcp_path = find_mcp_config(repo_path)
                    if mcp_path:
                        mcp_data = json.loads(mcp_path.read_text(encoding="utf-8"))
                        gjalla_env = mcp_data.get("mcpServers", {}).get("gjalla", {}).get("env", {})
                        mcp_key = gjalla_env.get("GJALLA_API_KEY")
                        if mcp_key and mcp_key != api_key:
                            info("  Trying API key from .mcp.json...")
                            mcp_api_url = gjalla_env.get("GJALLA_BASE_URL", api_url)
                            key_ok, key_detail = verify_api_key(mcp_key, mcp_api_url)
                            if key_ok:
                                api_key = mcp_key
                                api_url = mcp_api_url
                                key_source = "mcp_config"
                except (json.JSONDecodeError, OSError, ImportError):
                    pass
        if not key_ok:
            error(f"API key verification failed — {key_detail}")
            if key_source == "config":
                info("  The saved API key in ~/.gjalla/config.yaml is no longer valid.")
                info("  To provide a new key: gjalla init --api-key <key>")
                info("  Or set GJALLA_API_KEY in your environment")
            else:
                info(f"  API URL: {api_url}")
                info(f"  Key prefix: {api_key[:8]}..." if len(api_key) > 8 else "  Key: (too short)")
            raise SystemExit(1)
        success("API key verified")
        console.print()

        # Step 4: Discover/select project
        info("Step 4/8: Selecting project...")
        project_info = discover_or_select_project(repo_path, api_key, api_url, project_id)
        if not project_info:
            raise SystemExit(1)

        success(f"Selected project: {project_info.get('name', project_info['id'])}")
        console.print()

        # Save config with API key
        config["api_key"] = api_key
        config["api_url"] = api_url
        if "projects" not in config:
            config["projects"] = {}
        config["projects"][str(repo_path)] = str(project_info["id"])
        save_global_config(config)
    else:
        info("  Skipping steps 3-4 (API verification and project selection)")
        console.print()

    # Step 5: Create .gjalla project config
    info("Step 5/8: Creating .gjalla project config...")
    gjalla_dir = repo_path / ".gjalla"

    if gjalla_dir.is_file():
        migrate_gjalla_file_to_dir(repo_path)
        info("Migrated .gjalla file → .gjalla/config.yaml")
    gjalla_dir.mkdir(parents=True, exist_ok=True)

    gjalla_config_data = {
        "project_id": project_info["id"] if project_info else None,
        "api_url": api_url,
        "api_key_env": "GJALLA_API_KEY",
    }
    if local_arch_path:
        gjalla_config_data["local_arch_path"] = local_arch_path
    if local_rules_path:
        gjalla_config_data["local_rules_path"] = local_rules_path
    save_local_config(repo_path, gjalla_config_data)

    if project_info:
        success(f"Created .gjalla/config.yaml (project {project_info['id']})")
    elif local_arch_path or local_rules_path:
        paths = []
        if local_arch_path:
            paths.append(f"arch: {local_arch_path}")
        if local_rules_path:
            paths.append(f"rules: {local_rules_path}")
        success(f"Created .gjalla/config.yaml (local-only, {', '.join(paths)})")
    else:
        success("Created .gjalla/config.yaml (local-only, no project linked)")
    console.print()

    # Step 6: Update .gitignore
    info("Step 6/8: Updating .gitignore...")
    added = ensure_gitignore(repo_path, [".gjalla/.commit-attestation.yaml", ".gjalla/log.jsonl", ".gjalla/attestations/", ".gjalla/cache/"])
    if added:
        success(f"Added to .gitignore: {', '.join(added)}")
    else:
        success(".gitignore already up to date")
    console.print()

    # Step 7: Offer guardrails setup
    info("Step 7/8: Commit attestation guardrails...")
    info("This will add precommit hooks to your repository so agents must attest that their changes are compliant with your rules and architecture before committing.")
    if yes or Confirm.ask("Enable?", default=True):
        from ..hooks.scripts import attestation_pre_commit_script, post_commit_upload_script, example_attestation
        from ..hooks.installer import install_hooks, make_executable

        # Write example attestation
        example_path = gjalla_dir / "example-attestation.yaml"
        example_path.write_text(example_attestation(), encoding="utf-8")
        success("Created .gjalla/example-attestation.yaml")

        scripts_dir = repo_path / "scripts"
        scripts_dir.mkdir(exist_ok=True)

        pre_path = scripts_dir / "gjalla-attestation-check.sh"
        pre_path.write_text(attestation_pre_commit_script(), encoding="utf-8")
        make_executable(pre_path)

        post_path = scripts_dir / "gjalla-post-commit-upload.sh"
        post_path.write_text(post_commit_upload_script(), encoding="utf-8")
        make_executable(post_path)

        result = install_hooks(
            repo_path,
            pre_commit_command="bash scripts/gjalla-attestation-check.sh",
            post_commit_command="bash scripts/gjalla-post-commit-upload.sh",
        )
        success(f"Pre-commit: {result.pre_commit.message}")
        success(f"Post-commit: {result.post_commit.message}")

        # Generate agent guidance files (appends to CLAUDE.md etc.)
        from .setup import _generate_agent_guidance
        project_id_str = str(project_info["id"]) if project_info else "unknown"
        _generate_agent_guidance(repo_path, project_id_str, yes)
    else:
        info("Skipped. Run 'gjalla setup' later to enable guardrails.")
    console.print()

    # Step 8: MCP server for Claude Code
    info("Step 8/8: MCP server for Claude Code...")
    info("This adds a .mcp.json so Claude Code can access your project's architecture, rules, and context.")
    info("For other editors (Cursor, Windsurf, etc.), see https://gjalla.io/docs/mcp")
    if yes or Confirm.ask("Install for Claude Code?", default=True):
        from .mcp import install_gjalla_entry
        pid = project_info["id"] if project_info else None
        installed = install_gjalla_entry(repo_path, project_id=pid, api_url=api_url, api_key=api_key)
        if installed:
            success("gjalla MCP server configured in .mcp.json")
        else:
            info("gjalla MCP server already configured in .mcp.json")
    else:
        info("Skipped. Run 'gjalla mcp install' later to add MCP support.")
    console.print()

    # Build completion message
    if has_api_key:
        completion_msg = "[green]Success! Agents will now have to attest that their changes are compliant with your rules and architecture before committing[/green]\n\n"
        completion_msg += "Run 'gjalla sync' to refresh project context.\n"
        completion_msg += "Run 'gjalla setup' to reconfigure guardrails.\n"
        panel(completion_msg, title="gjalla initialized successfully!")
    else:
        completion_msg = "[green]Success! Local guardrails are active — agents must attest before committing.[/green]\n\n"
        completion_msg += "Connect a gjalla portal project to navigate architecture changes,\n"
        completion_msg += "configure centralized rules, enable PR reviews, and maintain lives context docs.\n\n"
        completion_msg += "  [bold]gjalla connect[/bold] — link your API key and project\n"
        panel(completion_msg, title="gjalla initialized (local-only)")
