"""Worker reputation model — tracks quality, trust tier, and reliability."""

from __future__ import annotations

import structlog

from hive_compute.coordinator.database import get_db_ctx

logger = structlog.get_logger()

# Trust tiers — canary and duplicate rates separated per marketplace roadmap.
# canary_rate: flat % of shards that are hidden known-answer tests (2% target)
# duplicate_rate: % of shards sent to a second worker for consensus validation
TRUST_TIERS = {
    "new": {"min_shards": 0, "min_quality": 0.0, "canary_rate": 0.02, "duplicate_rate": 1.0},
    "provisional": {"min_shards": 10, "min_quality": 0.7, "canary_rate": 0.02, "duplicate_rate": 0.2},
    "trusted": {"min_shards": 50, "min_quality": 0.85, "canary_rate": 0.02, "duplicate_rate": 0.1},
    "elite": {"min_shards": 200, "min_quality": 0.95, "canary_rate": 0.02, "duplicate_rate": 0.05},
}


def ensure_reputation(db, worker_id: str) -> None:
    """Create a reputation row if it doesn't exist."""
    db.execute(
        "INSERT OR IGNORE INTO worker_reputation (worker_id) VALUES (?)",
        (worker_id,),
    )


def record_shard_outcome(worker_id: str, success: bool, is_canary: bool = False, canary_passed: bool = False) -> None:
    """Record a shard outcome and update reputation."""
    with get_db_ctx() as db:
        ensure_reputation(db, worker_id)

        if success:
            db.execute(
                """
                UPDATE worker_reputation
                SET successful_shards = successful_shards + 1,
                    total_shards = total_shards + 1,
                    updated_at = datetime('now')
                WHERE worker_id = ?
                """,
                (worker_id,),
            )
        else:
            db.execute(
                """
                UPDATE worker_reputation
                SET failed_shards = failed_shards + 1,
                    total_shards = total_shards + 1,
                    updated_at = datetime('now')
                WHERE worker_id = ?
                """,
                (worker_id,),
            )

        if is_canary:
            if canary_passed:
                db.execute(
                    "UPDATE worker_reputation SET canary_passes = canary_passes + 1 WHERE worker_id = ?",
                    (worker_id,),
                )
            else:
                db.execute(
                    "UPDATE worker_reputation SET canary_fails = canary_fails + 1 WHERE worker_id = ?",
                    (worker_id,),
                )

        # Recompute quality score and tier
        _recompute(db, worker_id)


def _recompute(db, worker_id: str) -> None:
    """Recompute quality score and trust tier for a worker."""
    row = db.execute(
        "SELECT * FROM worker_reputation WHERE worker_id = ?",
        (worker_id,),
    ).fetchone()

    if not row or row["total_shards"] == 0:
        return

    # Quality score = success rate with canary weight
    base_quality = row["successful_shards"] / row["total_shards"]

    total_canaries = row["canary_passes"] + row["canary_fails"]
    if total_canaries > 0:
        canary_quality = row["canary_passes"] / total_canaries
        # Canaries count double because they're ground truth
        quality = (base_quality + 2 * canary_quality) / 3
    else:
        quality = base_quality

    # Determine trust tier
    new_tier = "new"
    for tier_name in ["elite", "trusted", "provisional"]:
        reqs = TRUST_TIERS[tier_name]
        if row["total_shards"] >= reqs["min_shards"] and quality >= reqs["min_quality"]:
            new_tier = tier_name
            break

    db.execute(
        """
        UPDATE worker_reputation
        SET quality_score = ?, trust_tier = ?, updated_at = datetime('now')
        WHERE worker_id = ?
        """,
        (round(quality, 4), new_tier, worker_id),
    )

    if new_tier != row["trust_tier"]:
        logger.info(
            "Worker trust tier changed",
            worker_id=worker_id,
            old_tier=row["trust_tier"],
            new_tier=new_tier,
            quality=round(quality, 4),
        )


def get_reputation(worker_id: str) -> dict | None:
    """Get a worker's reputation info."""
    with get_db_ctx() as db:
        row = db.execute(
            "SELECT * FROM worker_reputation WHERE worker_id = ?",
            (worker_id,),
        ).fetchone()

    if not row:
        return None

    return {
        "worker_id": row["worker_id"],
        "trust_tier": row["trust_tier"],
        "quality_score": row["quality_score"],
        "total_shards": row["total_shards"],
        "successful_shards": row["successful_shards"],
        "failed_shards": row["failed_shards"],
        "canary_passes": row["canary_passes"],
        "canary_fails": row["canary_fails"],
        "updated_at": row["updated_at"],
    }


def get_all_reputations() -> list[dict]:
    """Get reputation info for all workers."""
    with get_db_ctx() as db:
        rows = db.execute(
            "SELECT * FROM worker_reputation ORDER BY quality_score DESC"
        ).fetchall()

    return [
        {
            "worker_id": row["worker_id"],
            "trust_tier": row["trust_tier"],
            "quality_score": row["quality_score"],
            "total_shards": row["total_shards"],
            "successful_shards": row["successful_shards"],
            "failed_shards": row["failed_shards"],
        }
        for row in rows
    ]
