from __future__ import annotations
import json
from datetime import datetime, timezone
from pathlib import Path

from neurotron.logbus import logbus
from .neurotron_config import (
    NEUROTRON_DATASET_PATH,
    NEUROTRON_HISTORY_KEEP,
    NEUROTRON_DIAG_SCHEMA,
    HOMEOSTASIS_CPU_WARN,
    HOMEOSTASIS_CPU_ALERT,
    HOMEOSTASIS_MEM_WARN,
    HOMEOSTASIS_MEM_ALERT,
    HOMEOSTASIS_LOAD_WARN,
    HOMEOSTASIS_LOAD_ALERT,
)
from .perception import Perception


def _now_iso():
    return datetime.now(timezone.utc).isoformat()


class AutoDiagnostic:
    """
    Subsistema silencioso de diagnóstico do Neurotron.

    Responsabilidades:
        - recolher perceções internas (CPU, MEM, LOAD)
        - comparar com diagnóstico anterior
        - atualizar last_diagnostic.json
        - manter histórico (rolling)
        - atualizar telemetria contínua
        - emitir eventos para logbus (não para stdout)
    """

    def __init__(self, runtime_dir: str, log_dir: str):
        self.runtime_dir = Path(runtime_dir)
        self.log_dir = Path(log_dir)

        self.data_dir = Path(NEUROTRON_DATASET_PATH)
        self.data_dir.mkdir(parents=True, exist_ok=True)

        self.last_file = self.data_dir / "last_diagnostic.json"
        self.telemetry_file = self.data_dir / "telemetry.json"

        self.perception = Perception()

    # ----------------------------------------------------------------------
    # Utilitários internos
    # ----------------------------------------------------------------------

    def _load_previous(self):
        try:
            if self.last_file.exists():
                return json.loads(self.last_file.read_text())
        except Exception as e:
            logbus.emit(f"[diag.warn] falha ao ler último diagnóstico: {e}")
        return None

    def _save_current(self, payload):
        history = []
        prev = self._load_previous()

        if prev:
            history = prev.get("history", [])
            history.append({
                "timestamp": prev.get("timestamp"),
                "cpu_percent": prev.get("cpu_percent"),
                "mem_percent": prev.get("mem_percent"),
                "loadavg": prev.get("loadavg"),
                "state": prev.get("state", "UNKNOWN"),
            })
            history = history[-NEUROTRON_HISTORY_KEEP:]

        payload["history"] = history

        try:
            self.last_file.write_text(json.dumps(payload, indent=2))
        except Exception as e:
            logbus.emit(f"[diag.error] falha ao gravar diagnóstico: {e}")

    def _classify_state(self, cpu, mem, l1):
        try:
            cpu = float(cpu)
            mem = float(mem)
            l1  = float(l1)
        except Exception:
            return "UNKNOWN"

        if cpu >= HOMEOSTASIS_CPU_ALERT or mem >= HOMEOSTASIS_MEM_ALERT or l1 >= HOMEOSTASIS_LOAD_ALERT:
            return "CRITICAL"

        if cpu >= HOMEOSTASIS_CPU_WARN or mem >= HOMEOSTASIS_MEM_WARN or l1 >= HOMEOSTASIS_LOAD_WARN:
            return "ALERT"

        return "STABLE"

    # ----------------------------------------------------------------------
    # Execução principal
    # ----------------------------------------------------------------------

    def run_exam(self):
        """
        Realiza um diagnóstico silencioso, atualiza os ficheiros,
        e retorna (state, payload).
        """
        snap = self.perception.snapshot()

        cpu  = snap.get("cpu_percent", "?")
        mem  = snap.get("mem_percent", "?")
        load = snap.get("loadavg", ["?", "?", "?"])
        l1   = load[0] if isinstance(load, list) and load else "?"

        state = self._classify_state(cpu, mem, l1)

        payload = {
            "schema": NEUROTRON_DIAG_SCHEMA,
            "timestamp": _now_iso(),
            "cpu_percent": cpu,
            "mem_percent": mem,
            "loadavg": load,
            "state": state,
            "env": {
                "user": snap.get("env_user"),
                "term": snap.get("env_term"),
            },
        }

        self._save_current(payload)
        self._update_telemetry(payload)

        # Falamos apenas através do logbus
        logbus.emit(f"[diag] estado={state} cpu={cpu} mem={mem} load1={l1}")

        return state, payload

    # ----------------------------------------------------------------------

    def _update_telemetry(self, payload):
        try:
            telemetry = []
            if self.telemetry_file.exists():
                telemetry = json.loads(self.telemetry_file.read_text() or "[]")

            telemetry.append({
                "timestamp": payload["timestamp"],
                "cpu": payload.get("cpu_percent"),
                "mem": payload.get("mem_percent"),
                "load": payload.get("loadavg"),
                "state": payload.get("state"),
            })

            telemetry = telemetry[-128:]
            self.telemetry_file.write_text(json.dumps(telemetry, indent=2))

        except Exception as e:
            logbus.emit(f"[diag.warn] falha ao atualizar telemetria: {e}")

