"""Canary system — hidden known-answer tasks and duplicate sampling for quality control."""

from __future__ import annotations

import random
import uuid

import structlog

from hive_compute.coordinator.abuse_events import record_abuse_event
from hive_compute.coordinator.database import get_db_ctx, record_event
from hive_compute.coordinator.reputation import TRUST_TIERS, record_shard_outcome

logger = structlog.get_logger()


def add_canary(
    audio_url: str,
    expected_transcript: str,
    language: str = "en",
    duration_seconds: float = 30.0,
    difficulty: str = "normal",
) -> str:
    """Add a known-answer audio clip to the canary corpus."""
    canary_id = f"canary_{uuid.uuid4().hex[:12]}"

    with get_db_ctx() as db:
        db.execute(
            """
            INSERT INTO canary_corpus (
                canary_id,
                audio_url,
                expected_transcript,
                language,
                duration_seconds,
                difficulty
            )
            VALUES (?, ?, ?, ?, ?, ?)
            """,
            (canary_id, audio_url, expected_transcript, language, duration_seconds, difficulty),
        )

    logger.info("Canary added", canary_id=canary_id, duration=duration_seconds)
    return canary_id


def get_random_canary(language: str = "en") -> dict | None:
    """Pick a random canary from the corpus."""
    with get_db_ctx() as db:
        rows = db.execute(
            "SELECT * FROM canary_corpus WHERE language = ?",
            (language,),
        ).fetchall()

    if not rows:
        return None

    row = random.choice(rows)
    return {
        "canary_id": row["canary_id"],
        "audio_url": row["audio_url"],
        "expected_transcript": row["expected_transcript"],
        "language": row["language"],
        "duration_seconds": row["duration_seconds"],
    }


def should_inject_canary(worker_id: str) -> bool:
    """Decide whether to inject a canary — flat 2% rate across all tiers."""
    with get_db_ctx() as db:
        row = db.execute(
            "SELECT trust_tier FROM worker_reputation WHERE worker_id = ?",
            (worker_id,),
        ).fetchone()

    tier = row["trust_tier"] if row else "new"
    rate = TRUST_TIERS.get(tier, TRUST_TIERS["new"])["canary_rate"]

    return random.random() < rate


def should_duplicate_shard(worker_id: str) -> bool:
    """Decide whether to send this shard to a second worker for consensus validation.

    New workers get 100% duplicate validation.
    Elite workers get 5%.
    """
    with get_db_ctx() as db:
        row = db.execute(
            "SELECT trust_tier FROM worker_reputation WHERE worker_id = ?",
            (worker_id,),
        ).fetchone()

    tier = row["trust_tier"] if row else "new"
    rate = TRUST_TIERS.get(tier, TRUST_TIERS["new"])["duplicate_rate"]

    return random.random() < rate


def inject_canary_shard(job_id: str, worker_id: str) -> dict | None:
    """Create a hidden canary shard for a worker to process.

    The canary looks like a normal shard but has a known expected output.
    Returns the canary shard info if injected, None if no canaries available.
    """
    canary = get_random_canary()
    if not canary:
        return None

    shard_id = f"shard_{uuid.uuid4().hex[:12]}"

    with get_db_ctx() as db:
        # Create a canary shard that looks like normal work, with canary_id stored directly
        db.execute(
            """
            INSERT INTO shards (
                shard_id,
                job_id,
                shard_index,
                start_seconds,
                end_seconds,
                overlap_seconds,
                status,
                claimed_by,
                claimed_at,
                last_heartbeat,
                attempts,
                max_attempts,
                canary_id
            )
            VALUES (?, ?, -1, 0.0, ?, 0.0, 'claimed', ?, datetime('now'), datetime('now'), 1, 1, ?)
            """,
            (shard_id, job_id, canary["duration_seconds"], worker_id, canary["canary_id"]),
        )

        record_event(
            db, job_id, "canary_injected",
            to_status="claimed", actor="canary_system",
            detail=f"canary {canary['canary_id']} as shard {shard_id} for worker {worker_id}",
        )

    logger.info("Canary injected", shard_id=shard_id, canary_id=canary["canary_id"], worker_id=worker_id)

    return {
        "shard_id": shard_id,
        "canary_id": canary["canary_id"],
        "audio_url": canary["audio_url"],
        "expected_transcript": canary["expected_transcript"],
        "duration_seconds": canary["duration_seconds"],
        "language": canary["language"],
    }


def validate_canary_result(shard_id: str, worker_id: str, transcript: str) -> dict:
    """Check a worker's output against the known canary answer.

    Returns validation result with similarity score and pass/fail.
    """
    # Look up canary_id directly from the shard record
    with get_db_ctx() as db:
        shard = db.execute(
            "SELECT canary_id, job_id FROM shards WHERE shard_id = ?",
            (shard_id,),
        ).fetchone()

    if not shard or not shard["canary_id"]:
        return {"passed": False, "error": "No canary found for shard"}

    canary_id = shard["canary_id"]

    with get_db_ctx() as db:
        canary = db.execute(
            "SELECT * FROM canary_corpus WHERE canary_id = ?",
            (canary_id,),
        ).fetchone()

    if not canary:
        return {"passed": False, "error": "Canary not found in corpus"}

    expected = canary["expected_transcript"]
    similarity = compute_transcript_similarity(expected, transcript)
    from hive_compute.config import get_settings
    threshold = get_settings().validated_canary_threshold()
    passed = similarity >= threshold

    # Record validation result
    job_id = shard["job_id"]

    with get_db_ctx() as db:
        db.execute(
            """
            INSERT INTO validation_results
                (shard_id, job_id, worker_id, validation_type, expected_text, actual_text,
                 similarity_score, passed, detail)
            VALUES (?, ?, ?, 'canary', ?, ?, ?, ?, ?)
            """,
            (
                shard_id, job_id, worker_id,
                expected[:500], transcript[:500],
                similarity, 1 if passed else 0,
                f"canary={canary_id}, threshold={threshold}",
            ),
        )

    if not passed:
        record_abuse_event(
            subject_type="worker",
            subject_id=worker_id,
            event_type="canary_failed",
            severity="high",
            detail=f"canary={canary_id}, similarity={round(similarity, 4)}, threshold={threshold}",
            job_id=job_id,
            shard_id=shard_id,
        )

    # Update reputation
    record_shard_outcome(worker_id, success=passed, is_canary=True, canary_passed=passed)

    logger.info(
        "Canary validated",
        worker_id=worker_id,
        canary_id=canary_id,
        similarity=round(similarity, 3),
        passed=passed,
    )

    return {
        "canary_id": canary_id,
        "similarity": round(similarity, 4),
        "passed": passed,
        "threshold": threshold,
    }


def compute_transcript_similarity(expected: str, actual: str) -> float:
    """Compute normalized word-level similarity between two transcripts.

    Uses token overlap (Jaccard-like) with case/punctuation normalization.
    Good enough for canary validation — not meant for production NLP.
    """
    def normalize(text: str) -> set[str]:
        # Lowercase, strip punctuation, split into words
        cleaned = "".join(c if c.isalnum() or c.isspace() else " " for c in text.lower())
        return set(cleaned.split())

    expected_words = normalize(expected)
    actual_words = normalize(actual)

    if not expected_words and not actual_words:
        return 1.0
    if not expected_words or not actual_words:
        return 0.0

    intersection = expected_words & actual_words
    union = expected_words | actual_words

    return len(intersection) / len(union)
