# retoor <retoor@molodetz.nl>
from __future__ import annotations

import json
import logging
import shutil
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Optional

from devplacepy.config import ISSLOP_MEDIA_DIR
from devplacepy.database import get_table

logger = logging.getLogger(__name__)

TABLE_ANALYSES = "isslop_analyses"
TABLE_EVENTS = "isslop_events"
TABLE_FILE_RESULTS = "isslop_file_results"
TABLE_IMAGE_RESULTS = "isslop_image_results"
TABLE_DOM_RESULTS = "isslop_dom_results"
TABLE_REPORTS = "isslop_reports"

EVENT_LIMIT_DEFAULT = 2000
EVENT_PAYLOAD_CAP = 60000
SIGNALS_CAP = 30000
LIST_LIMIT_DEFAULT = 50


def utc_now() -> str:
    return datetime.now(timezone.utc).isoformat()


def create_analysis(uid: str, source_url: str, owner_kind: str, owner_id: str) -> dict[str, Any]:
    row: dict[str, Any] = {
        "uid": uid,
        "owner_kind": owner_kind,
        "owner_id": owner_id,
        "source_url": source_url,
        "source_kind": "unknown",
        "status": "pending",
        "created_at": utc_now(),
        "finished_at": None,
        "content_hash": None,
        "grade": None,
        "slop_score": None,
        "origin_score": None,
        "quality_deficit_score": None,
        "human_percent": None,
        "ai_percent": None,
        "category": None,
        "confidence": None,
        "files_total": 0,
        "files_analyzed": 0,
        "error_message_text": None,
        "deleted_at": None,
        "deleted_by": None,
    }
    get_table(TABLE_ANALYSES).insert(row)
    return row


def update_analysis(uid: str, **fields: Any) -> None:
    fields["uid"] = uid
    get_table(TABLE_ANALYSES).update(fields, ["uid"])


def get_analysis(uid: str) -> Optional[dict[str, Any]]:
    row = get_table(TABLE_ANALYSES).find_one(uid=uid, deleted_at=None)
    return dict(row) if row else None


def list_analyses(owner_kind: str, owner_id: str, limit: int = LIST_LIMIT_DEFAULT) -> list[dict[str, Any]]:
    rows = get_table(TABLE_ANALYSES).find(
        owner_kind=owner_kind,
        owner_id=owner_id,
        deleted_at=None,
        order_by=["-created_at"],
        _limit=limit,
    )
    return [dict(row) for row in rows]


def claim_guest_analyses(guest_id: str, user_uid: str) -> int:
    table = get_table(TABLE_ANALYSES)
    rows = list(table.find(owner_kind="guest", owner_id=guest_id, deleted_at=None))
    for row in rows:
        table.update({"uid": row["uid"], "owner_kind": "user", "owner_id": user_uid}, ["uid"])
    if rows:
        logger.info("Claimed %d guest isslop analyses for user %s", len(rows), user_uid)
    return len(rows)


def insert_event(analysis_uid: str, seq: int, kind: str, message: str, payload: str) -> None:
    get_table(TABLE_EVENTS).insert(
        {
            "analysis_uid": analysis_uid,
            "seq": seq,
            "kind": kind,
            "message": message,
            "payload": payload[:EVENT_PAYLOAD_CAP],
            "created_at": utc_now(),
        }
    )


def events_for(analysis_uid: str, after_seq: int = 0, limit: int = EVENT_LIMIT_DEFAULT) -> list[dict[str, Any]]:
    rows = get_table(TABLE_EVENTS).find(
        analysis_uid=analysis_uid,
        seq={">": after_seq},
        order_by=["seq"],
        _limit=limit,
    )
    return [dict(row) for row in rows]


def insert_file_result(analysis_uid: str, record: dict[str, Any]) -> None:
    record["analysis_uid"] = analysis_uid
    get_table(TABLE_FILE_RESULTS).insert(record)


def file_result_for(analysis_uid: str, path: str) -> Optional[dict[str, Any]]:
    row = get_table(TABLE_FILE_RESULTS).find_one(analysis_uid=analysis_uid, path=path)
    return dict(row) if row else None


def file_results_for(analysis_uid: str) -> list[dict[str, Any]]:
    rows = get_table(TABLE_FILE_RESULTS).find(analysis_uid=analysis_uid, order_by=["path"])
    return [dict(row) for row in rows]


def insert_image_result(analysis_uid: str, record: dict[str, Any]) -> None:
    record["analysis_uid"] = analysis_uid
    get_table(TABLE_IMAGE_RESULTS).insert(record)


def image_results_for(analysis_uid: str) -> list[dict[str, Any]]:
    rows = get_table(TABLE_IMAGE_RESULTS).find(analysis_uid=analysis_uid, order_by=["-ai_probability"])
    return [dict(row) for row in rows]


def insert_dom_result(analysis_uid: str, record: dict[str, Any]) -> None:
    record["analysis_uid"] = analysis_uid
    get_table(TABLE_DOM_RESULTS).insert(record)


def dom_results_for(analysis_uid: str) -> list[dict[str, Any]]:
    rows = get_table(TABLE_DOM_RESULTS).find(analysis_uid=analysis_uid, order_by=["-signal_count"])
    return [dict(row) for row in rows]


def save_report(analysis_uid: str, markdown: str, model_used: str) -> None:
    get_table(TABLE_REPORTS).upsert(
        {
            "analysis_uid": analysis_uid,
            "markdown": markdown,
            "model_used": model_used,
            "generated_at": utc_now(),
        },
        ["analysis_uid"],
    )


def get_report(analysis_uid: str) -> Optional[dict[str, Any]]:
    row = get_table(TABLE_REPORTS).find_one(analysis_uid=analysis_uid)
    return dict(row) if row else None


def decode_json(field: Any, fallback: Any) -> Any:
    if not field:
        return fallback
    try:
        parsed = json.loads(field)
    except (ValueError, TypeError):
        return fallback
    return parsed if isinstance(parsed, type(fallback)) else fallback


def media_dir_for(uid: str) -> Path:
    return ISSLOP_MEDIA_DIR / uid


def reset_evidence(uid: str) -> None:
    get_table(TABLE_EVENTS).delete(analysis_uid=uid)
    get_table(TABLE_FILE_RESULTS).delete(analysis_uid=uid)
    get_table(TABLE_IMAGE_RESULTS).delete(analysis_uid=uid)
    get_table(TABLE_DOM_RESULTS).delete(analysis_uid=uid)
    get_table(TABLE_REPORTS).delete(analysis_uid=uid)
    shutil.rmtree(media_dir_for(uid), ignore_errors=True)


def purge_analysis(uid: str) -> None:
    reset_evidence(uid)
    get_table(TABLE_ANALYSES).delete(uid=uid)
