"""Install attestation infrastructure in a repository."""

import json
import os
import stat
from pathlib import Path

import click

from ..display.output import console, success, error, warning, info, panel
from ..hooks.installer import install_hooks
from ..hooks.scripts import attestation_pre_commit_script, post_commit_upload_script, example_attestation


def _get_repo_root() -> Path:
    """Find git repository root from current directory."""
    cwd = Path.cwd()
    for parent in [cwd, *cwd.parents]:
        if (parent / ".git").exists():
            return parent
    raise click.ClickException("Not in a git repository")


def _ensure_gitignore(repo_root: Path, entries: list[str]) -> None:
    """Ensure entries exist in .gitignore."""
    gitignore = repo_root / ".gitignore"
    existing = gitignore.read_text() if gitignore.exists() else ""
    lines = existing.splitlines()
    added = []
    for entry in entries:
        if entry not in lines:
            lines.append(entry)
            added.append(entry)
    if added:
        gitignore.write_text("\n".join(lines) + "\n")
        info(f"Added to .gitignore: {', '.join(added)}")


def _get_gjalla_config(repo_root: Path) -> dict | None:
    """Read .gjalla/config.json, handling old file-based format."""
    gjalla_dir = repo_root / ".gjalla"
    config_path = gjalla_dir / "config.json"

    # New format: .gjalla/config.json
    if config_path.is_file():
        try:
            return json.loads(config_path.read_text())
        except (json.JSONDecodeError, OSError):
            return None

    # Old format: .gjalla as a plain JSON file — migrate
    if gjalla_dir.is_file():
        try:
            config = json.loads(gjalla_dir.read_text())
            # Migrate to directory format
            old_content = gjalla_dir.read_text()
            gjalla_dir.unlink()
            gjalla_dir.mkdir(parents=True, exist_ok=True)
            config_path.write_text(old_content)
            info("Migrated .gjalla file → .gjalla/config.json")
            return config
        except (json.JSONDecodeError, OSError):
            return None

    return None


@click.command()
@click.option(
    "--hooks/--no-hooks",
    default=True,
    help="Install git hooks (default: yes).",
)
def setup(hooks: bool) -> None:
    """Install attestation guardrails in this repository.

    Sets up the commit attestation gate:

    \b
    1. Verifies .gjalla project config exists
    2. Creates example attestation + hook scripts
    3. Updates .gitignore
    4. Optionally installs git hooks

    \b
    Examples:
        gjalla setup              # Full setup with hooks
        gjalla setup --no-hooks   # Scripts only, wire hooks yourself
    """
    repo_root = _get_repo_root()

    panel("Gjalla Guardrails Setup", title="gjalla setup")
    console.print()

    # Step 1: Verify .gjalla config exists
    config = _get_gjalla_config(repo_root)
    if config is None:
        gjalla_dir = repo_root / ".gjalla"
        if not gjalla_dir.exists():
            error("No .gjalla config found. Run 'gjalla init' first.")
        else:
            error("Invalid .gjalla config. Run 'gjalla init' to recreate.")
        raise SystemExit(1)

    info(f"Project: {config.get('project_id', 'unknown')}")

    # Step 2: Write example attestation
    gjalla_dir = repo_root / ".gjalla"
    gjalla_dir.mkdir(parents=True, exist_ok=True)
    example_path = gjalla_dir / "example-attestation.md"
    example_path.write_text(example_attestation())
    success(f"Created {example_path.relative_to(repo_root)}")

    # Step 3: Write attestation scripts
    scripts_dir = repo_root / "scripts"
    scripts_dir.mkdir(exist_ok=True)

    pre_commit_path = scripts_dir / "gjalla-attestation-check.sh"
    pre_commit_path.write_text(attestation_pre_commit_script())
    pre_commit_path.chmod(pre_commit_path.stat().st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
    success(f"Created {pre_commit_path.relative_to(repo_root)}")

    post_commit_path = scripts_dir / "gjalla-post-commit-upload.sh"
    post_commit_path.write_text(post_commit_upload_script())
    post_commit_path.chmod(post_commit_path.stat().st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
    success(f"Created {post_commit_path.relative_to(repo_root)}")

    # Step 4: Update .gitignore
    _ensure_gitignore(repo_root, [".commit-attestation.md", ".gjallalog"])

    # Step 5: Install hooks
    if hooks:
        result = install_hooks(
            repo_root,
            pre_commit_command="bash scripts/gjalla-attestation-check.sh",
            post_commit_command="bash scripts/gjalla-post-commit-upload.sh",
        )
        if result.pre_commit.status.value in ("installed", "added_to_existing"):
            success(f"Pre-commit hook: {result.pre_commit.message}")
        else:
            warning(f"Pre-commit hook: {result.pre_commit.message}")

        if result.post_commit.status.value in ("installed", "added_to_existing"):
            success(f"Post-commit hook: {result.post_commit.message}")
        else:
            warning(f"Post-commit hook: {result.post_commit.message}")
    else:
        info("Skipping hook installation (--no-hooks)")

    console.print()
    panel(
        "[green]Guardrails installed![/green]\n\n"
        "Agents must create .commit-attestation.md before committing.\n"
        "Example format: .gjalla/example-attestation.md\n"
        "Humans can skip with: SKIP_ATTESTATION=1 git commit ...\n\n"
        "[dim]If you use simple-git-hooks, husky, or pre-commit.org:[/dim]\n"
        "  pre-commit: bash scripts/gjalla-attestation-check.sh\n"
        "  post-commit: bash scripts/gjalla-post-commit-upload.sh",
        title="Setup Complete",
    )
