"""Upload attestations to Gjalla cloud."""

import json
import subprocess
from pathlib import Path

import click
import httpx

from ..config.settings import Settings
from ..display.output import console, info, success, warning, error


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 _upload_attestations(settings: Settings, repo_root: Path) -> None:
    """Upload attestations to Gjalla cloud."""
    gjalla_config = repo_root / ".gjalla" / "config.json"
    if not gjalla_config.exists():
        # Check old format
        old_config = repo_root / ".gjalla"
        if old_config.is_file():
            gjalla_config = old_config
        else:
            info("No .gjalla config — skipping attestation upload")
            return

    try:
        config = json.loads(gjalla_config.read_text())
        project_id = config.get("project_id")
        api_url = config.get("api_url", settings.api_url)
    except (json.JSONDecodeError, OSError):
        warning("Invalid .gjalla config — skipping attestation upload")
        return

    if not project_id:
        warning("No project_id in .gjalla config")
        return

    # Read attestation file if present and append to log
    attestation_path = repo_root / ".commit-attestation.md"
    gjallalog_path = repo_root / ".gjallalog"

    if attestation_path.exists():
        _log_attestation(attestation_path, gjallalog_path)
        attestation_path.unlink()
        info("Logged attestation and cleaned up .commit-attestation.md")

    # Upload unsent log entries
    if not gjallalog_path.exists():
        info("No attestation log entries to upload")
        return

    api_key = settings.api_key
    if not api_key:
        warning("No API key configured — attestations logged locally only")
        return

    lines = gjallalog_path.read_text().strip().splitlines()
    unsent = []
    for line in lines:
        try:
            entry = json.loads(line)
            if not entry.get("uploaded"):
                unsent.append(entry)
        except json.JSONDecodeError:
            pass

    if not unsent:
        info("All attestations already uploaded")
        return

    info(f"Uploading {len(unsent)} attestation(s)...")

    try:
        response = httpx.post(
            f"{api_url}/api/agent/projects/{project_id}/attestations",
            headers={
                "x-api-key": api_key,
                "Content-Type": "application/json",
            },
            json={"attestations": unsent},
            timeout=30.0,
        )

        if response.status_code == 200:
            data = response.json()
            inserted = data.get("inserted", 0)
            success(f"Uploaded {inserted} attestation(s)")

            # Mark all as uploaded
            updated_lines = []
            for line in lines:
                try:
                    entry = json.loads(line)
                    entry["uploaded"] = True
                    updated_lines.append(json.dumps(entry))
                except json.JSONDecodeError:
                    updated_lines.append(line)
            gjallalog_path.write_text("\n".join(updated_lines) + "\n")
        else:
            warning(f"Upload failed (HTTP {response.status_code}). Entries saved locally.")
    except httpx.RequestError as e:
        warning(f"Upload failed: {e}. Entries saved locally.")


def _log_attestation(attestation_path: Path, gjallalog_path: Path) -> None:
    """Parse attestation file and append JSONL entry to log."""
    content = attestation_path.read_text()
    fields: dict[str, str] = {}
    for line in content.splitlines():
        line = line.strip()
        if ":" in line and not line.startswith("#") and not line.startswith("---"):
            key, _, value = line.partition(":")
            key = key.strip().replace(" ", "_")
            value = value.strip().strip("\"'")
            if key and value:
                fields[key] = value

    # Get commit hash and branch
    try:
        result = subprocess.run(
            ["git", "rev-parse", "HEAD"],
            capture_output=True, text=True,
        )
        commit = result.stdout.strip() if result.returncode == 0 else "unknown"
    except OSError:
        commit = "unknown"

    try:
        result = subprocess.run(
            ["git", "rev-parse", "--abbrev-ref", "HEAD"],
            capture_output=True, text=True,
        )
        branch = result.stdout.strip() if result.returncode == 0 else "unknown"
    except OSError:
        branch = "unknown"

    entry = {
        "ts": fields.get("timestamp", ""),
        "commit": commit,
        "branch": branch,
        "agent": fields.get("agent", ""),
        "agent_provider": fields.get("agent_provider", ""),
        "agent_model": fields.get("agent_model", ""),
        "rules_checked": fields.get("rules.checked", "false").lower() == "true"
            or fields.get("checked", "false").lower() == "true",
        "services": fields.get("services_affected", "").split(",") if fields.get("services_affected") else [],
        "tech": fields.get("tech_stack_used", "").split(",") if fields.get("tech_stack_used") else [],
        "arch_change": fields.get("architecture.changes", "false").lower() == "true"
            or fields.get("changes", "false").lower() == "true",
        "summary": fields.get("summary", ""),
        "uploaded": False,
    }

    with open(gjallalog_path, "a") as f:
        f.write(json.dumps(entry) + "\n")


@click.command()
def sync() -> None:
    """Upload pending attestations to Gjalla cloud.

    Reads the local .gjallalog file and uploads any entries
    that haven't been sent yet.

    \b
    Examples:
        gjalla sync    # Upload pending attestations
    """
    repo_root = _get_repo_root()

    console.print("[bold]Gjalla Sync[/bold]")
    console.print()

    settings = Settings.load()
    if not settings.api_key:
        error("API key not configured. Run 'gjalla init' first.")
        raise SystemExit(1)

    info("[bold]Uploading attestations...[/bold]")
    _upload_attestations(settings, repo_root)
