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

import json
import logging
from typing import Any

from devplacepy.services.jobs.isslop import store
from devplacepy.services.jobs.isslop.events import (
    KIND_DOM,
    KIND_DONE,
    KIND_ERROR,
    KIND_FILE,
    KIND_IMAGE,
    KIND_REPORT,
    WorkerEvent,
)

logger = logging.getLogger(__name__)

SCORE_FIELDS: tuple[str, ...] = (
    "grade",
    "slop_score",
    "origin_score",
    "human_percent",
    "ai_percent",
    "category",
    "confidence",
    "content_hash",
    "source_kind",
    "files_total",
    "files_analyzed",
    "detected_builder",
)

ERROR_MESSAGE_CAP = 2000
TELLS_CAP = 4000
DESCRIPTION_CAP = 2000


class EventPersister:
    def __init__(self, analysis_uid: str) -> None:
        self._analysis_uid = analysis_uid
        self._seq = 0

    @property
    def seq(self) -> int:
        return self._seq

    @property
    def analysis_uid(self) -> str:
        return self._analysis_uid

    def apply(self, event: WorkerEvent) -> dict[str, Any]:
        self._seq += 1
        payload_for_storage = dict(event.data)
        if event.kind == KIND_REPORT:
            markdown = str(payload_for_storage.pop("markdown", ""))
            model_used = str(payload_for_storage.get("model_used", "unknown"))
            store.save_report(self._analysis_uid, markdown, model_used)
        store.insert_event(
            self._analysis_uid,
            self._seq,
            event.kind,
            event.message,
            json.dumps(payload_for_storage, ensure_ascii=False),
        )
        if event.kind == KIND_FILE:
            store.insert_file_result(
                self._analysis_uid,
                {
                    "path": str(event.data.get("path", "")),
                    "language": str(event.data.get("language", "unknown")),
                    "lines": int(event.data.get("sloc", 0)),
                    "origin_score": float(event.data.get("origin_score", 0.0)),
                    "quality_deficit_score": float(event.data.get("quality_deficit", 0.0)),
                    "category": str(event.data.get("category", "uncertain")),
                    "signals": json.dumps(event.data.get("signals", []), ensure_ascii=False)[: store.SIGNALS_CAP],
                    "source": str(event.data.get("source") or ""),
                },
            )
        if event.kind == KIND_IMAGE:
            store.insert_image_result(
                self._analysis_uid,
                {
                    "path": str(event.data.get("path", "")),
                    "ai_probability": float(event.data.get("ai_probability", 0.0)),
                    "grade": str(event.data.get("grade", "n/a")),
                    "verdict": str(event.data.get("verdict", "uncertain")),
                    "image_kind": str(event.data.get("image_kind", "image")),
                    "tells": json.dumps(event.data.get("tells", []), ensure_ascii=False)[:TELLS_CAP],
                    "description": str(event.data.get("description", ""))[:DESCRIPTION_CAP],
                    "thumb": str(event.data.get("thumb") or ""),
                },
            )
        if event.kind == KIND_DOM:
            store.insert_dom_result(
                self._analysis_uid,
                {
                    "url": str(event.data.get("url", "")),
                    "detected_builder": str(event.data.get("detected_builder") or ""),
                    "signal_count": int(event.data.get("signal_count", 0)),
                    "screenshot": str(event.data.get("screenshot") or ""),
                    "signals": json.dumps(event.data.get("signals", []), ensure_ascii=False)[: store.SIGNALS_CAP],
                },
            )
        if event.kind == KIND_DONE:
            updates: dict[str, Any] = {
                key: event.data.get(key) for key in SCORE_FIELDS if key in event.data
            }
            updates["quality_deficit_score"] = event.data.get("quality_deficit")
            updates["dom_slop_score"] = event.data.get("dom_slop_score")
            updates["status"] = "completed"
            updates["finished_at"] = store.utc_now()
            store.update_analysis(self._analysis_uid, **updates)
        if event.kind == KIND_ERROR:
            store.update_analysis(
                self._analysis_uid,
                status="failed",
                finished_at=store.utc_now(),
                error_message_text=event.message[:ERROR_MESSAGE_CAP],
            )
        return {
            "analysis": self._analysis_uid,
            "seq": self._seq,
            "kind": event.kind,
            "message": event.message,
            "data": payload_for_storage if event.kind != KIND_FILE else event.data,
            "created_at": store.utc_now(),
        }
