"""Cohesive workflow helpers for exploit mitigation analysis."""

from __future__ import annotations

from typing import Any, cast

from ..domain.services.exploit_mitigation import (
    build_dll_characteristics_result,
    build_safe_seh_entry,
    parse_load_config,
)
from .exploit_mitigation_rules import DLL_CHARACTERISTICS


def analyze_exploit_mitigations(analyzer: Any, *, logger: Any) -> dict[str, Any]:
    result = analyzer._init_result_structure(
        {
            "mitigations": {},
            "dll_characteristics": {},
            "load_config": {},
            "security_score": 0,
            "recommendations": [],
            "vulnerabilities": [],
        }
    )
    try:
        result["available"] = True
        analyzer._check_dll_characteristics(result)
        analyzer._check_safe_seh(result)
        analyzer._check_load_config(result)
        analyzer._check_stack_cookies(result)
        analyzer._check_authenticode(result)
        analyzer._check_pe_security_features(result)
        analyzer._calculate_security_score(result)
        analyzer._generate_recommendations(result)
        return cast(dict[str, Any], result)
    except Exception as e:
        logger.error("Error analyzing exploit mitigations: %s", e)
        result["available"] = False
        result["mitigations"] = {}
        result["error"] = str(e)
        return cast(dict[str, Any], result)


def check_dll_characteristics(analyzer: Any, result: dict[str, Any], *, logger: Any) -> None:
    try:
        optional_header = analyzer._cmdj("iHj", {})
        if not optional_header or not isinstance(optional_header, dict):
            return
        dll_characteristics = optional_header.get("dll_characteristics", 0)
        details, mitigations = build_dll_characteristics_result(
            dll_characteristics,
            DLL_CHARACTERISTICS,
        )
        result["dll_characteristics"] = details
        result["mitigations"].update(mitigations)
    except Exception as e:
        logger.error("Error checking DllCharacteristics: %s", e)


def check_safe_seh(analyzer: Any, result: dict[str, Any], *, logger: Any) -> None:
    try:
        if analyzer._has_no_seh_flag(result):
            analyzer._set_safe_seh(result, False, "Binary has NO_SEH flag set")
            return
        load_config_dir = analyzer._get_load_config_dir()
        if not load_config_dir:
            analyzer._set_safe_seh(result, False, "No data directories found")
            return
        if analyzer._load_config_present(load_config_dir):
            analyzer._set_safe_seh(result, True, "Load Configuration present")
            return
        analyzer._set_safe_seh(result, False, "No SafeSEH table found")
    except Exception as e:
        logger.error("Error checking SafeSEH: %s", e)
        result["mitigations"]["SafeSEH"] = build_safe_seh_entry(enabled=False, error=str(e))


def check_load_config(analyzer: Any, result: dict[str, Any], *, logger: Any) -> None:
    try:
        load_config_dir = analyzer._get_load_config_dir()
        if not load_config_dir or load_config_dir.get("vaddr", 0) == 0:
            result["load_config"] = {
                "present": False,
                "note": "No Load Configuration Directory",
            }
            return

        offset = load_config_dir.get("paddr", 0)
        size = load_config_dir.get("size", 0)
        if offset == 0 or size == 0:
            return

        is_64bit = analyzer._is_pe_64bit()
        config_data = analyzer._read_load_config_data(offset, size)
        if not config_data:
            return

        result["load_config"] = parse_load_config(
            config_data,
            size,
            offset,
            is_64bit,
            result["mitigations"],
        )
    except Exception as e:
        logger.error("Error checking Load Configuration: %s", e)


def get_load_config_dir(analyzer: Any) -> dict[str, Any] | None:
    data_dirs = analyzer._cmdj("iDj", [])
    if not data_dirs or not isinstance(data_dirs, list):
        return None
    for dd in data_dirs:
        if isinstance(dd, dict) and dd.get("name") == "LOAD_CONFIG":
            return dd
    return None


def load_config_present(analyzer: Any, load_config_dir: dict[str, Any]) -> bool:
    offset = load_config_dir.get("paddr", 0)
    if offset <= 0:
        return False
    config_data = analyzer._cmdj(f"pxj 64 @ {hex(offset)}", [])
    return bool(config_data and len(config_data) >= 64)


def is_pe_64bit(analyzer: Any) -> bool:
    optional_header = analyzer._cmdj("iHj", {})
    return bool(optional_header and optional_header.get("magic", "") == "PE32+")


def read_load_config_data(analyzer: Any, offset: int, size: int) -> list[int]:
    read_size = min(size, 256)
    raw = analyzer._cmdj(f"pxj {read_size} @ {hex(offset)}", [])
    return cast(list[int], raw) if isinstance(raw, list) else []
