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

import json
import subprocess
from pathlib import Path

import click
import httpx
import yaml

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


def _upload_attestations(settings: Settings, repo_root: Path, attestations_dir: 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 — attestations logged locally only")
        return

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

    if attestation_path.exists():
        _log_attestation(attestation_path, gjallalog_path, attestations_dir)
        attestation_path.unlink()
        info("Logged attestation and cleaned up .gjalla/.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)
            # Backward compat: handle both "uploaded" and "synced" keys
            if not entry.get("uploaded") and not entry.get("synced"):
                # For new-format entries (no embedded attestation), load from file
                if "attestation" not in entry and "raw_attestation" not in entry:
                    commit = entry.get("commit", "")
                    att_file = attestations_dir / f"{commit}.yaml"
                    if att_file.exists():
                        entry["attestation"] = yaml.safe_load(att_file.read_text()) or {}
                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
                    entry["synced"] = 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 _parse_attestation_yaml(content: str) -> dict:
    """Parse attestation YAML frontmatter, stripping --- delimiters."""
    stripped = content.strip()
    if stripped.startswith("---"):
        stripped = stripped[3:]
    if stripped.endswith("---"):
        stripped = stripped[:-3]
    try:
        return yaml.safe_load(stripped) or {}
    except yaml.YAMLError:
        return {}


def _log_attestation(attestation_path: Path, gjallalog_path: Path, attestations_dir: Path) -> None:
    """Parse attestation YAML, save full body to file, append minimal entry to log."""
    content = attestation_path.read_text()
    parsed = _parse_attestation_yaml(content)

    # 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"

    # Save full attestation to individual YAML file
    attestations_dir.mkdir(parents=True, exist_ok=True)
    att_file = attestations_dir / f"{commit}.yaml"
    att_file.write_text(yaml.dump(parsed, default_flow_style=False, sort_keys=False))

    # Append minimal entry to .gjallalog
    entry = {
        "commit": commit,
        "branch": branch,
        "timestamp": parsed.get("timestamp", ""),
        "agent": parsed.get("agent", ""),
        "summary": parsed.get("summary", ""),
        "synced": False,
    }

    with open(gjallalog_path, "a") as f:
        f.write(json.dumps(entry, default=str) + "\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' or 'gjalla connect' first.")
        raise SystemExit(1)

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