from collections.abc import Iterable
import json
from typing import Any
from Copilot.SituationLayer.Core.Incident import IncidentRef
from Copilot.LLMLayer.Core.TagMaps import RULE_HIT_LABELS, INCIDENT_EVENT_LABELS


def replace_with_mapping(values, mapping):
    def _map_value(value):
        if value in mapping:
            return mapping[value]

        print(f"[WARNING] No mapping found for: {value}")
        return value

    # Single value (including Enum, str, int, etc.)
    if isinstance(values, (str, bytes)) or not isinstance(values, Iterable):
        return _map_value(values)

    # List, tuple, set, ...
    return [_map_value(v) for v in values]



def incident_to_llm_context(incident: IncidentRef, dump=True) -> str:

    context: dict[str, Any] = {
        "incident": {
            "type": replace_with_mapping(incident.incident_type, INCIDENT_EVENT_LABELS) ,
            "severity": str(incident.severity.value),
            "summary": incident.summary,
        },

        "machine": {
            "id": incident.machine.id,
            "name": incident.machine.display_name,
        },

        "trigger": {
            "parameter": incident.trigger_parameter.display_name,
            "value": incident.trigger_value,
            "timestamp": incident.trigger_timestamp.isoformat(),
            "rules": replace_with_mapping( incident.trigger_rules, RULE_HIT_LABELS ),
        },

        "window": {
            "start": incident.metadata.get("start"),
            "end": incident.metadata.get("end"),
            "signal_count": incident.metadata.get("count"),
        },

        "active_signals": [
            {
                "parameter": s.parameter.display_name,
                "value": s.value,
                "status": str(s.status.value),
                "trend": str(s.trend.value),
                "timestamp": s.timestamp.isoformat(),
                "rules": replace_with_mapping( s.rule_hits, RULE_HIT_LABELS ),
            }
            for s in incident.active_signals
        ],

        "machine_snapshot": [
            {
                "parameter": snap.parameter.display_name,
                "value": snap.value,
                "status": str(snap.status.value),
                "trend": str(snap.trend.value),
                "timestamp": snap.timestamp.isoformat(),
            }
            for snap in incident.machine_snapshot
        ],

        "parameter_histories": [
            {
                "parameter": hist.parameter.display_name,
                "samples": [
                    {
                        "timestamp": s.timestamp.isoformat(),
                        "value": s.value,
                        "status": str(s.status.value),
                        "trend": str(s.trend.value),
                    }
                    for s in hist.samples
                ]
            }
            for hist in incident.parameter_histories
        ],
    }

    return context

def llm_json_dumps(context:dict):
    return json.dumps(
        context,
        ensure_ascii=False,
        indent=2,
        default=str
    )