"""Sync business logic — reusable by CLI and daemon."""

from __future__ import annotations

import json
import subprocess

from rich.console import Console

from syke.config import user_data_dir, user_profile_path
from syke.db import SykeDB


def detect_github_username(db: SykeDB, user_id: str) -> str | None:
    """Detect GitHub username from DB metadata (prior ingest) or gh CLI."""
    row = db.conn.execute(
        "SELECT metadata FROM events WHERE user_id = ? AND source = 'github' AND event_type = 'profile' LIMIT 1",
        (user_id,),
    ).fetchone()
    if row:
        try:
            meta = json.loads(row[0]) if isinstance(row[0], str) else row[0]
            login = meta.get("login")
            if login:
                return login
        except (json.JSONDecodeError, TypeError, AttributeError):
            pass

    try:
        r = subprocess.run(
            ["gh", "api", "user", "--jq", ".login"],
            capture_output=True, text=True, timeout=10,
        )
        if r.returncode == 0 and r.stdout.strip():
            return r.stdout.strip()
    except (FileNotFoundError, subprocess.TimeoutExpired):
        pass

    return None


def sync_source(
    db: SykeDB, user_id: str, source: str, tracker, log: Console,
) -> int:
    """Sync a single source. Returns count of new events."""
    if source == "chatgpt":
        log.print(f"  [dim]SKIP[/dim] chatgpt (one-time import)")
        return 0

    if source == "github":
        gh_username = detect_github_username(db, user_id)
        if not gh_username:
            log.print(f"  [yellow]SKIP[/yellow] github — could not detect username")
            return 0
        from syke.ingestion.github_ import GitHubAdapter
        adapter = GitHubAdapter(db, user_id)
        kwargs = {"username": gh_username}
        label = f"github (@{gh_username})"
    elif source == "claude-code":
        from syke.ingestion.claude_code import ClaudeCodeAdapter
        adapter = ClaudeCodeAdapter(db, user_id)
        kwargs = {}
        label = "claude-code"
    elif source == "gmail":
        from syke.ingestion.gmail import GmailAdapter
        adapter = GmailAdapter(db, user_id)
        kwargs = {}
        label = "gmail"
    else:
        log.print(f"  [dim]SKIP[/dim] {source} (unknown)")
        return 0

    with tracker.track(f"sync_{source}") as metrics:
        result = adapter.ingest(**kwargs)
        metrics.events_processed = result.events_count

    if result.events_count > 0:
        log.print(f"  [green]+{result.events_count}[/green] {label}")
    else:
        log.print(f"  [dim] 0[/dim] {label}")
    return result.events_count


def run_sync(
    db: SykeDB,
    user_id: str,
    full_perceive: bool = False,
    skip_perception: bool = False,
    use_agentic: bool = True,
    out: Console | None = None,
) -> tuple[int, list[str]]:
    """Core sync logic reusable by CLI and daemon.

    Returns (total_new_events, list_of_synced_sources).
    """
    from syke.metrics import MetricsTracker

    tracker = MetricsTracker(user_id)
    log = out or Console()

    sources = db.get_sources(user_id)
    if not sources:
        return 0, []

    total_new = 0
    synced: list[str] = []

    for source in sources:
        count = sync_source(db, user_id, source, tracker, log)
        total_new += count
        if count >= 0 and source != "chatgpt":
            synced.append(source)

    # Also count events pushed via MCP (federated push path) since last perception.
    last_profile_ts = db.get_last_profile_timestamp(user_id)
    if last_profile_ts:
        pushed_since = db.count_events_since(user_id, last_profile_ts)
        extra_pushed = max(0, pushed_since - total_new)
        if extra_pushed > 0:
            log.print(f"  [green]+{extra_pushed}[/green] pushed events (via MCP)")
            total_new += extra_pushed

    # Skip perception if no new events
    if total_new == 0:
        log.print("  [dim]No new events, skipping perception[/dim]")
        return 0, synced

    # Perception
    if not skip_perception:
        mode = "full" if full_perceive else "incremental"

        if use_agentic:
            log.print(f"\n  [cyan]Running agentic {mode} perception...[/cyan]")
            from syke.perception.agentic_perceiver import AgenticPerceiver

            with tracker.track("sync_perceive_agentic", mode=mode) as metrics:
                perceiver = AgenticPerceiver(db, user_id)
                profile = perceiver.perceive(full=full_perceive)
                metrics.events_processed = profile.events_count
                metrics.cost_usd = profile.cost_usd
        else:
            log.print(f"\n  [cyan]Running {mode} perception...[/cyan]")
            from syke.perception.perceiver import Perceiver

            with tracker.track("sync_perceive", mode=mode) as metrics:
                perceiver = Perceiver(db, user_id)
                profile = perceiver.perceive(full=full_perceive)
                metrics.events_processed = profile.events_count
                metrics.cost_usd = profile.cost_usd
                metrics.input_tokens = perceiver.client.total_input_tokens
                metrics.output_tokens = perceiver.client.total_output_tokens

        profile_path = user_profile_path(user_id)
        profile_path.write_text(profile.model_dump_json(indent=2))

        from syke.distribution.formatters import format_profile

        for fmt, filename in [("claude-md", "CLAUDE.md"), ("user-md", "USER.md")]:
            path = user_data_dir(user_id) / filename
            path.write_text(format_profile(profile, fmt))

        log.print(f"  [green]Profile updated.[/green] Cost: ${profile.cost_usd:.4f}")
    elif total_new > 0 and skip_perception:
        log.print(f"\n  [dim]Skipping perception (--skip-perception).[/dim]")

    return total_new, synced
