"""Payout ledger — tracks worker earnings with holdback and release logic."""

from __future__ import annotations

import math

import structlog

from hive_compute.coordinator.database import get_db_ctx, record_event

logger = structlog.get_logger()

DEFAULT_WORKER_RATE_PER_MINUTE = 0.001  # $0.001/min = ~$0.06/hr

# Hold periods by trust tier
HOLD_DAYS = {
    "new": 14,
    "provisional": 7,
    "trusted": 3,
    "elite": 1,
}


def create_payout_item(
    worker_id: str,
    job_id: str,
    duration_seconds: float,
    shard_id: str | None = None,
    rate_per_minute: float = DEFAULT_WORKER_RATE_PER_MINUTE,
) -> int:
    """Create a payout row for completed work. Returns amount in cents.

    Payouts are aggregated per worker per job (not per shard) to minimize
    rounding inflation. ceil() ensures workers are never underpaid.
    """
    duration_minutes = duration_seconds / 60.0
    amount_cents = math.ceil(duration_minutes * rate_per_minute * 100)

    # Determine hold period from worker trust tier
    with get_db_ctx() as db:
        rep = db.execute(
            "SELECT trust_tier FROM worker_reputation WHERE worker_id = ?",
            (worker_id,),
        ).fetchone()
        tier = rep["trust_tier"] if rep else "new"
        hold_days = HOLD_DAYS.get(tier, 14)
        hold_until_row = db.execute(
            "SELECT datetime('now', ?) as hold_until",
            (f"+{hold_days} days",),
        ).fetchone()
        hold_until = hold_until_row["hold_until"]

        # UNIQUE index on (shard_id, worker_id) prevents double-payout atomically
        result = db.execute(
            """
            INSERT OR IGNORE INTO payout_items (worker_id, job_id, shard_id, duration_seconds,
                                      rate_per_minute, amount_cents, hold_until)
            VALUES (?, ?, ?, ?, ?, ?, ?)
            """,
            (worker_id, job_id, shard_id, duration_seconds, rate_per_minute, amount_cents, hold_until),
        )
        if result.rowcount == 0:
            logger.warning("Payout already exists for shard", shard_id=shard_id)
            return 0

        record_event(
            db, job_id, "payout_created",
            to_status="completed", actor="payouts",
            detail=f"worker={worker_id}, {amount_cents}¢, hold until {hold_until[:10]}",
        )

    logger.info("Payout created", worker_id=worker_id, amount_cents=amount_cents, hold_days=hold_days)
    return amount_cents


def release_held_payouts() -> int:
    """Release payouts that have passed their hold period. Returns count released."""
    with get_db_ctx() as db:
        result = db.execute(
            """
            UPDATE payout_items SET status = 'released', released_at = datetime('now')
            WHERE status = 'held' AND hold_until <= datetime('now')
            """,
        )
        released = result.rowcount

    if released:
        logger.info("Payouts released", count=released)
    return released


def reverse_payout(payout_id: int, reason: str) -> bool:
    """Reverse a payout (e.g., after fraud detection). Creates a reversal record."""
    with get_db_ctx() as db:
        row = db.execute(
            "SELECT * FROM payout_items WHERE payout_id = ? AND reversed_at IS NULL",
            (payout_id,),
        ).fetchone()

        if not row:
            return False

        db.execute(
            "UPDATE payout_items SET status = 'reversed', reversed_at = datetime('now') WHERE payout_id = ?",
            (payout_id,),
        )

        record_event(
            db, row["job_id"], "payout_reversed",
            to_status="completed", actor="payouts",
            detail=f"payout {payout_id} reversed: {reason}",
        )

    logger.info("Payout reversed", payout_id=payout_id, reason=reason)
    return True


def get_worker_earnings(worker_id: str) -> dict:
    """Get earnings summary for a worker."""
    with get_db_ctx() as db:
        rows = db.execute(
            """
            SELECT status, SUM(amount_cents) as total, COUNT(*) as cnt
            FROM payout_items WHERE worker_id = ? AND reversed_at IS NULL
            GROUP BY status
            """,
            (worker_id,),
        ).fetchall()

    earnings = {"held": 0, "released": 0, "total": 0, "items": 0}
    for row in rows:
        earnings[row["status"]] = row["total"] or 0
        earnings["items"] += row["cnt"]
    earnings["total"] = earnings["held"] + earnings["released"]

    return {"worker_id": worker_id, **earnings}


def record_payout_disbursement(worker_id: str, amount_usd: float, note: str | None = None) -> dict:
    """Record a manual payout event for a worker."""
    amount_cents = math.ceil(amount_usd * 100)
    with get_db_ctx() as db:
        row = db.execute(
            """
            INSERT INTO worker_payout_events (worker_id, amount_cents, note)
            VALUES (?, ?, ?)
            RETURNING payout_event_id, worker_id, amount_cents, status, note, created_at
            """,
            (worker_id, amount_cents, note),
        ).fetchone()

    return {
        "payout_event_id": row["payout_event_id"],
        "worker_id": row["worker_id"],
        "amount_usd": round(row["amount_cents"] / 100.0, 2),
        "status": row["status"],
        "note": row["note"],
        "created_at": row["created_at"],
    }


def list_payout_disbursements(worker_id: str) -> list[dict]:
    with get_db_ctx() as db:
        rows = db.execute(
            """
            SELECT payout_event_id, amount_cents, status, note, created_at
            FROM worker_payout_events
            WHERE worker_id = ?
            ORDER BY created_at DESC, payout_event_id DESC
            """,
            (worker_id,),
        ).fetchall()

    return [
        {
            "payout_event_id": row["payout_event_id"],
            "amount_usd": round(row["amount_cents"] / 100.0, 2),
            "status": row["status"],
            "note": row["note"],
            "created_at": row["created_at"],
        }
        for row in rows
    ]
