from __future__ import annotations

import hashlib
import hmac
import json
from typing import Any

from app.core.expense_application_fingerprint_keys import (
    ACTIVE_FINGERPRINT_KEY_VERSION,
    get_expense_application_fingerprint_key,
)

FINGERPRINT_KEY_VERSION = ACTIVE_FINGERPRINT_KEY_VERSION

FACT_KEYS = (
    "application_type",
    "time",
    "location",
    "reason",
    "days",
    "transport_mode",
    "amount",
    "grade",
    "department",
    "position",
    "manager_name",
    "lodging_daily_cap",
    "subsidy_daily_cap",
    "transport_policy",
    "policy_estimate",
    "matched_city",
    "rule_name",
    "rule_version",
    "hotel_amount",
    "allowance_amount",
    "transport_estimated_amount",
    "transport_estimate_source",
    "transport_estimate_confidence",
    "policy_total_amount",
)

PREVIEW_FIELD_ALIASES = {
    "applicationType": "application_type",
    "application_type": "application_type",
    "time": "time",
    "time_return": "time",
    "location": "location",
    "reason": "reason",
    "days": "days",
    "transportMode": "transport_mode",
    "transport_mode": "transport_mode",
    "amount": "amount",
    "grade": "grade",
    "department": "department",
    "position": "position",
    "managerName": "manager_name",
    "manager_name": "manager_name",
}

PREVIEW_RESPONSE_KEYS = {
    "application_type": "applicationType",
    "time": "time",
    "location": "location",
    "reason": "reason",
    "days": "days",
    "transport_mode": "transportMode",
    "amount": "amount",
    "grade": "grade",
    "department": "department",
    "position": "position",
    "manager_name": "managerName",
    "lodging_daily_cap": "lodgingDailyCap",
    "subsidy_daily_cap": "subsidyDailyCap",
    "transport_policy": "transportPolicy",
    "policy_estimate": "policyEstimate",
    "matched_city": "matchedCity",
    "rule_name": "ruleName",
    "rule_version": "ruleVersion",
    "hotel_amount": "hotelAmount",
    "allowance_amount": "allowanceAmount",
    "transport_estimated_amount": "transportEstimatedAmount",
    "transport_estimate_source": "transportEstimateSource",
    "transport_estimate_confidence": "transportEstimateConfidence",
    "policy_total_amount": "policyTotalAmount",
}


def safe_text(value: object, limit: int = 500) -> str:
    return str(value or "").strip()[:limit]


def safe_fact_snapshot(facts: dict[str, Any]) -> dict[str, str]:
    return {key: value for key in FACT_KEYS if (value := safe_text(facts.get(key)))}


def canonical_preview_fields(preview: dict[str, Any]) -> dict[str, str]:
    fields = preview.get("fields") if isinstance(preview, dict) else None
    if not isinstance(fields, dict):
        return {}
    values: dict[str, str] = {}
    for alias, field_key in PREVIEW_FIELD_ALIASES.items():
        value = safe_text(fields.get(alias))
        if value:
            values[field_key] = value
    return values


def preview_response_fields(facts: dict[str, Any]) -> dict[str, str]:
    snapshot = safe_fact_snapshot(facts)
    return {
        response_key: snapshot[field_key]
        for field_key, response_key in PREVIEW_RESPONSE_KEYS.items()
        if field_key in snapshot
    }


def hmac_fingerprint(
    payload: object,
    *,
    key_version: str = FINGERPRINT_KEY_VERSION,
    allow_key_creation: bool = True,
) -> str:
    serialized = _serialize(payload)
    secret_key = get_expense_application_fingerprint_key(
        key_version,
        create=allow_key_creation,
    )
    digest = hmac.new(
        secret_key,
        b"expense-application-preview:v1:" + serialized,
        hashlib.sha256,
    ).hexdigest()
    return f"hmac-sha256:{digest}"


def content_fingerprint(payload: object) -> str:
    return f"sha256:{hashlib.sha256(_serialize(payload)).hexdigest()}"


def field_value_fingerprint(
    value: str,
    *,
    present: bool,
    key_version: str = FINGERPRINT_KEY_VERSION,
    allow_key_creation: bool = True,
) -> str:
    return hmac_fingerprint(
        {"present": present, "value": value if present else ""},
        key_version=key_version,
        allow_key_creation=allow_key_creation,
    )


def field_fingerprints(
    values: dict[str, str],
    *,
    key_version: str = FINGERPRINT_KEY_VERSION,
    allow_key_creation: bool = True,
) -> dict[str, str]:
    return {
        key: field_value_fingerprint(
            value,
            present=True,
            key_version=key_version,
            allow_key_creation=allow_key_creation,
        )
        for key, value in sorted(values.items())
    }


def snapshot_reference(
    values: dict[str, str],
    *,
    key_version: str = FINGERPRINT_KEY_VERSION,
    allow_key_creation: bool = True,
) -> dict[str, Any]:
    return {
        "field_keys": sorted(values),
        "value_fingerprint": hmac_fingerprint(
            values,
            key_version=key_version,
            allow_key_creation=allow_key_creation,
        ),
        "fingerprint_key_version": key_version,
    }


def _serialize(payload: object) -> bytes:
    return json.dumps(
        payload,
        ensure_ascii=False,
        sort_keys=True,
        separators=(",", ":"),
        default=str,
    ).encode("utf-8")
