"""
Refusal Response Builder — Profile-Aware Rendering

Constitutional Compliance:
- F9 Anti-Hantu: No "I feel", "I care", "I want" language
- F6 Empathy: At least 2 safe alternatives
- F2 Truth: Non-accusatory reason, no exploit hints
- F1 Amanah: Privacy-safe logging (hash + redaction)

DITEMPA BUKAN DIBERI — Forged, not given.
"""

import hashlib
import json
import os
from datetime import datetime, timezone
from pathlib import Path
from typing import List, Dict, Any, Optional

from .types import RefusalType, RiskDomain, RefusalResponse
from .templates import DOMAIN_TEMPLATES, SKIN_TEMPLATES


def load_refusal_config(profile: str = "equilibrium_default") -> Dict[str, Any]:
    """
    Load refusal configuration from spec/v55/refusals.json.
    
    Args:
        profile: One of "enterprise_defensible", "consumer_survivable", "equilibrium_default"
    
    Returns:
        Profile configuration dict
    """
    config_path = Path(__file__).parent.parent.parent.parent / "spec" / "v55" / "refusals.json"
    
    if not config_path.exists():
        # Fallback to default config
        return {
            "skin": "consumer",
            "logging": {
                "store_redacted_excerpt": True,
                "include_policy_codes": True,
                "include_risk_score": True
            },
            "appeal": {
                "keyword": "REVIEW"
            }
        }
    
    with open(config_path) as f:
        full_config = json.load(f)
    
    return full_config.get("profiles", {}).get(profile, full_config["profiles"]["equilibrium_default"])


def _redact_prompt(prompt: str, max_length: int = 50) -> str:
    """
    Redact prompt for logging (privacy-safe).
    
    Args:
        prompt: User prompt to redact
        max_length: Maximum excerpt length (default: 50)
    
    Returns:
        Redacted string like "[REDACTED: 123 chars] First 20..."
    """
    if len(prompt) <= max_length:
        return f"[REDACTED: {len(prompt)} chars]"
    return f"[REDACTED: {len(prompt)} chars] {prompt[:20]}..."


def generate_refusal_response(
    prompt: str,
    refusal_type: RefusalType,
    risk_domain: RiskDomain,
    reason: str,
    policy_codes: List[str],
    risk_score: float,
    profile: str = "equilibrium_default"
) -> RefusalResponse:
    """
    Generate constitutionally compliant refusal with profile-aware rendering.
    
    INVARIANT (Constitutional Governance):
    The refusal decision (type, domain, risk_score) MUST NOT depend on presentation profile.
    Profiles affect wording and receipts only, never the verdict itself.
    This preserves governance integrity: decision logic is deterministic and profile-independent.
    
    Critical Rules:
    - Reason must be non-accusatory (no "you are trying to...")
    - Reason must not provide exploit hints
    - Must provide at least 2 safe alternatives
    - F9 Anti-Hantu compliant (no "I feel", "I care")
    
    Args:
        prompt: User prompt (for logging, never returned in response)
        refusal_type: One of R1-R5
        risk_domain: Risk category (violence, medical, etc.)
        reason: Plain-language explanation (non-accusatory)
        policy_codes: Constitutional floors triggered (e.g., ["F1", "F5"])
        risk_score: 0.0-1.0 risk assessment
        profile: "enterprise_defensible", "consumer_survivable", or "equilibrium_default"
    
    Returns:
        RefusalResponse with 4 layers (verdict, reason, alternatives, appeal)
    """
    
    # Load profile config
    config = load_refusal_config(profile)
    skin = config.get("skin", "consumer")
    
    # Get verdict template
    verdict_key = f"verdict_{refusal_type.value.lower()}"
    verdict = SKIN_TEMPLATES.get(skin, SKIN_TEMPLATES["consumer"])["copy"].get(
        verdict_key, "I can't help with that."
    )
    
    # Get domain-specific templates
    template = DOMAIN_TEMPLATES.get(risk_domain.value, DOMAIN_TEMPLATES["other"])
    
    # Use template reason if provided reason is empty or default
    if not reason or reason in ["policy", "safety", "risk"]:
        reason = template.get("reason", reason)
    
    # Get alternatives from template
    alternatives = template.get("alternatives", [
        "I can help you reformulate your request.",
        "I can explain the risks and constraints."
    ])
    
    # Ensure at least 2 alternatives (F6 Empathy)
    if len(alternatives) < 2:
        alternatives.append("I can provide general information on this topic.")
    
    # Generate appeal instructions
    appeal_keyword = config.get("appeal", {}).get("keyword", "REVIEW")
    appeal_instructions = f"If you think this was misunderstood, reply '{appeal_keyword}' with context."
    
    # Generate trace ID
    trace_id = hashlib.sha256(
        f"{prompt}{datetime.now(timezone.utc).isoformat()}".encode()
    ).hexdigest()[:16]
    
    # Build log data (privacy-safe)
    log_data = {
        "trace_id": trace_id,
        "query_hash": hashlib.sha256(prompt.encode()).hexdigest()[:16],
        "timestamp": datetime.now(timezone.utc).isoformat(),
        "model_version": "v55.2",
        "profile": profile,
        "redacted_excerpt": (
            _redact_prompt(prompt) 
            if config.get("logging", {}).get("store_redacted_excerpt", False) 
            else None
        )
    }
    
    return RefusalResponse(
        refusal_type=refusal_type,
        risk_domain=risk_domain,
        verdict=verdict,
        reason=reason,
        safe_alternatives=alternatives,
        appeal_instructions=appeal_instructions,
        policy_codes=policy_codes,
        risk_score=risk_score,
        appealable=refusal_type != RefusalType.R5_RATE,
        trace_id=trace_id,
        log_data=log_data
    )
