"""Bounded, operator-invoked durable Strava sync smoke support; never a production sync policy."""

from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime, timezone
from pathlib import Path

from mountain_twin.activity import User
from mountain_twin.activity.persistence import (
    ActivitySqliteDatabase,
    DurableSyncCoordinator,
    OpaqueProviderState,
    PersistentIngestionResult,
    SqliteActivityIdentityStore,
    SyncFrontierPolicy,
    SyncMode,
    SyncRunStatus,
)

from .ingestion import PersistentStravaIngestionService

DEFAULT_SMOKE_ACTIVITY_COUNT = 3
MAX_SMOKE_ACTIVITY_COUNT = 5
MAX_SMOKE_PROVIDER_REQUESTS = 1
OWNER_CREATED_AT = "2026-01-01T00:00:00+00:00"


@dataclass(frozen=True)
class PersistentStravaSmokeResult:
    database_path: Path
    sync_source_id: str
    sync_run_id: str
    status: SyncRunStatus
    requested_activity_count: int
    acquired_activity_count: int
    pages_completed: int
    activities_persisted: int
    authoritative_frontier_present_before: bool
    authoritative_frontier_present_after: bool
    ingestions: tuple[PersistentIngestionResult, ...]


def validate_smoke_count(count: int) -> int:
    if count <= 0 or count > MAX_SMOKE_ACTIVITY_COUNT:
        raise ValueError(f"smoke activity count must be between 1 and {MAX_SMOKE_ACTIVITY_COUNT}")
    return count


def prepare_smoke_database(
    database_path: Path,
    *,
    reuse_database: bool,
    repository_root: Path | None = None,
) -> ActivitySqliteDatabase:
    """Create a new ignored local database or require explicit reuse; never reset it."""
    root = repository_root or Path(__file__).resolve().parents[3]
    local_root = (root / "data" / "local").resolve()
    ignored_marker = "data/local/"
    if ignored_marker not in (root / ".gitignore").read_text(encoding="utf-8").splitlines():
        raise ValueError("data/local must be gitignored before using the persistent smoke harness")
    resolved = database_path.resolve()
    try:
        resolved.relative_to(local_root)
    except ValueError as error:
        raise ValueError("smoke database must be under the ignored data/local directory") from error
    if resolved.exists() and not reuse_database:
        raise FileExistsError("smoke database already exists; pass --reuse-db to reuse it intentionally")
    resolved.parent.mkdir(parents=True, exist_ok=True)
    return ActivitySqliteDatabase(resolved)


def run_bounded_strava_smoke(
    database: ActivitySqliteDatabase,
    *,
    adapter,
    user_id: str,
    provider_subject_id: str,
    count: int = DEFAULT_SMOKE_ACTIVITY_COUNT,
    observed_at: str | None = None,
) -> PersistentStravaSmokeResult:
    """Acquire and process exactly one page, then complete the bounded diagnostic plan."""
    count = validate_smoke_count(count)
    observed_at = observed_at or datetime.now(timezone.utc).isoformat()
    store = SqliteActivityIdentityStore(database)
    user = User(user_id, OWNER_CREATED_AT)
    source = store.resolve_provider_sync_source(user, "strava", provider_subject_id, observed_at)
    frontier_before = _has_authoritative_frontier(store, source.sync_source_id)
    plan = OpaqueProviderState(
        "strava_persistent_smoke_plan_v0_1",
        {
            "diagnostic": "bounded_persistent_smoke",
            "max_activity_count": count,
            "max_provider_requests": MAX_SMOKE_PROVIDER_REQUESTS,
            "per_page": count,
        },
    )
    run = store.create_sync_run(
        source.sync_source_id,
        SyncMode.BOUNDED,
        plan,
        OpaqueProviderState("strava_persistent_smoke_resume_v0_1", {"page": 1}),
        observed_at,
        frontier_policy=SyncFrontierPolicy.NONE,
    )
    store.transition_sync_run(run.sync_run_id, SyncRunStatus.RUNNING, observed_at)
    ingestion = PersistentStravaIngestionService(store, user)
    ingestions: list[PersistentIngestionResult] = []

    def persist(payload: dict) -> PersistentIngestionResult:
        result = ingestion.ingest_activity(payload, fetched_at=observed_at)
        ingestions.append(result)
        return result

    coordinator = DurableSyncCoordinator(store, adapter, persist)
    status = coordinator.execute_next_page(
        run.sync_run_id,
        observed_at,
        complete_requested_plan=True,
    )
    completed = store.get_sync_run(run.sync_run_id)
    result = PersistentStravaSmokeResult(
        Path(database.path),
        source.sync_source_id,
        run.sync_run_id,
        status,
        count,
        len(ingestions),
        completed.pages_completed,
        completed.activities_persisted,
        frontier_before,
        _has_authoritative_frontier(store, source.sync_source_id),
        tuple(ingestions),
    )
    store.close()
    return result


def diagnostics_for_smoke(result: PersistentStravaSmokeResult) -> dict:
    """Return identities and counters only; provider payloads and Activity content stay private."""
    return {
        "database_path": str(result.database_path),
        "sync_source_id": result.sync_source_id,
        "sync_run_id": result.sync_run_id,
        "status": result.status.value,
        "requested_activity_count": result.requested_activity_count,
        "acquired_activity_count": result.acquired_activity_count,
        "pages_completed": result.pages_completed,
        "activities_persisted": result.activities_persisted,
        "authoritative_frontier_present_before": result.authoritative_frontier_present_before,
        "authoritative_frontier_present_after": result.authoritative_frontier_present_after,
        "ingestions": [
            {
                "activity_entity_id": item.activity_entity_id,
                "source_link_id": item.source_link_id,
                "raw_record_id": item.raw_record_id,
                "activity_revision_id": item.activity_revision_id,
                "entity_created": item.entity_created,
                "raw_payload_created": item.raw_payload_created,
                "raw_record_created": item.raw_record_created,
                "revision_created": item.revision_created,
                "provenance_attached": item.provenance_attached,
                "current_revision_changed": item.current_revision_changed,
            }
            for item in result.ingestions
        ],
    }


def _has_authoritative_frontier(store: SqliteActivityIdentityStore, sync_source_id: str) -> bool:
    try:
        store.get_authoritative_frontier(sync_source_id)
    except KeyError:
        return False
    return True
