"""
Cross-Border Data Transfer Governance Engine for GDPR + DPDPA

GDPR Requirements:
- Article 44-50: Cross-border transfers
- Article 46: Standard Contractual Clauses (SCCs)
- Schrems II: Transfer Impact Assessment (TIA)

DPDPA Requirements:
- Section 16(1)-(2): Negative list model (transfers permitted unless restricted)
- Rule 15: Transfers subject to requirements the Central Government specifies by
  general or special order (making data available to a foreign State or its entities)
- Rule 6: Security safeguards that travel with the data

This engine validates cross-border transfers against BOTH frameworks before allowing
data to leave the origin jurisdiction.

Requirements:
    - Python 3.9+
    - pydantic>=2.5.0
    - requests>=2.31.0 (for API calls to compliance endpoints)

Usage:
    python transfer_governance_engine.py
    # Or integrate as library:
    from transfer_governance_engine import TransferGovernanceEngine
    engine = TransferGovernanceEngine(config_file="transfer_config.yaml")
    result = engine.evaluate_transfer("eu", "india", data_category="personal_data")
"""

from datetime import datetime, timezone
from enum import Enum
from typing import Dict, List, Optional
from dataclasses import dataclass, field
import logging

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


# =============================================================================
# Data Models
# =============================================================================

class Jurisdiction(str, Enum):
    """Supported jurisdictions"""
    EU = "eu"
    INDIA = "india"
    US = "us"
    UK = "uk"
    SINGAPORE = "singapore"
    OTHER = "other"


class DataCategory(str, Enum):
    """Data categories for transfer evaluation"""
    PERSONAL_DATA = "personal_data"
    SENSITIVE_DATA = "sensitive_data"  # Special category per GDPR Article 9
    FINANCIAL_DATA = "financial_data"  # Subject to RBI rules
    HEALTH_DATA = "health_data"
    CHILDREN_DATA = "children_data"


class TransferMechanism(str, Enum):
    """GDPR transfer mechanisms"""
    ADEQUACY_DECISION = "adequacy_decision"
    SCC = "standard_contractual_clauses"
    BCR = "binding_corporate_rules"
    DEROGATION = "derogation"
    NOT_APPLICABLE = "not_applicable"  # For non-GDPR transfers


class TransferDecision(str, Enum):
    """Transfer approval decision"""
    APPROVED = "approved"
    DENIED = "denied"
    MANUAL_REVIEW_REQUIRED = "manual_review_required"


@dataclass
class TransferRequest:
    """Cross-border transfer request"""
    origin_jurisdiction: Jurisdiction
    destination_jurisdiction: Jurisdiction
    data_category: DataCategory
    data_volume_records: int
    processor_name: str
    processor_contract_id: Optional[str] = None
    scc_executed: bool = False
    tia_conducted: bool = False
    consent_obtained: bool = False
    request_timestamp: datetime = field(default_factory=lambda: datetime.now(timezone.utc))


@dataclass
class TransferEvaluation:
    """Result of transfer evaluation"""
    decision: TransferDecision
    gdpr_compliant: bool
    dpdpa_compliant: bool
    decision_rationale: str
    required_actions: List[str]
    warnings: List[str]
    evaluated_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))


# =============================================================================
# Transfer Governance Configuration
# =============================================================================

@dataclass
class TransferGovernanceConfig:
    """
    Configuration for cross-border transfer governance
    Load from YAML/JSON file in production
    """
    # GDPR: EU adequacy decisions (as of April 2026)
    eu_adequacy_countries: List[str] = field(default_factory=lambda: [
        "andorra", "argentina", "canada", "faroe_islands", "guernsey",
        "israel", "isle_of_man", "japan", "jersey", "new_zealand",
        "republic_of_korea", "switzerland", "uk", "uruguay"
    ])

    # DPDPA: Section 16 restricted countries (as of April 2026)
    # NOTE: Empty list as of April 2026 — no country has been restricted
    dpdpa_restricted_countries: List[str] = field(default_factory=list)

    # Sectoral restrictions (e.g., RBI for financial data)
    rbi_restricted_countries: List[str] = field(default_factory=lambda: [
        # Example: Countries with weak AML controls
        # Update based on latest RBI circular
    ])

    # Security safeguards required for all cross-border transfers (DPDPA Rule 6)
    required_safeguards: List[str] = field(default_factory=lambda: [
        "encryption_at_rest",       # Rule 6(1)(a)
        "encryption_in_transit",    # Rule 6(1)(a)
        "access_control",           # Rule 6(1)(b)
        "logging_enabled",          # Rule 6(1)(c)
        "log_retention_1_year",     # Rule 6(1)(e)
        "processor_contract",       # Rule 6(1)(f) + Section 8(2)
    ])

    # Auto-deny thresholds
    high_risk_data_volume_threshold: int = 100000  # Records
    require_manual_review_for_sensitive: bool = True


# =============================================================================
# Transfer Governance Engine
# =============================================================================

class TransferGovernanceEngine:
    """
    Evaluates cross-border data transfers against GDPR and DPDPA requirements
    """

    def __init__(self, config: Optional[TransferGovernanceConfig] = None):
        """
        Initialize engine with configuration

        Args:
            config: Transfer governance configuration (or use defaults)
        """
        self.config = config or TransferGovernanceConfig()

    def evaluate_transfer(self, request: TransferRequest) -> TransferEvaluation:
        """
        Evaluate a cross-border data transfer request

        Args:
            request: TransferRequest with origin, destination, data category, etc.

        Returns:
            TransferEvaluation with approval decision and rationale
        """
        logger.info(f"Evaluating transfer: {request.origin_jurisdiction} → {request.destination_jurisdiction}")

        gdpr_result = self._evaluate_gdpr(request)
        dpdpa_result = self._evaluate_dpdpa(request)

        # Combine results
        decision = self._make_final_decision(gdpr_result, dpdpa_result, request)

        evaluation = TransferEvaluation(
            decision=decision["decision"],
            gdpr_compliant=gdpr_result["compliant"],
            dpdpa_compliant=dpdpa_result["compliant"],
            decision_rationale=decision["rationale"],
            required_actions=decision["required_actions"],
            warnings=decision["warnings"]
        )

        logger.info(f"Transfer decision: {evaluation.decision.value}")
        return evaluation

    def _evaluate_gdpr(self, request: TransferRequest) -> Dict:
        """
        Evaluate GDPR compliance for cross-border transfer

        GDPR applies if origin is EU or data subjects are EU residents
        """
        if request.origin_jurisdiction != Jurisdiction.EU:
            return {
                "compliant": True,
                "applicable": False,
                "rationale": "GDPR does not apply (origin not EU)"
            }

        # GDPR Article 44-50: Transfer outside EEA requires valid mechanism
        dest_country = request.destination_jurisdiction.value

        # Check for adequacy decision
        if dest_country in self.config.eu_adequacy_countries:
            return {
                "compliant": True,
                "applicable": True,
                "mechanism": TransferMechanism.ADEQUACY_DECISION,
                "rationale": f"GDPR Article 45: {dest_country} has EU adequacy decision"
            }

        # Check for Standard Contractual Clauses
        if request.scc_executed:
            if request.tia_conducted:
                return {
                    "compliant": True,
                    "applicable": True,
                    "mechanism": TransferMechanism.SCC,
                    "rationale": "GDPR Article 46: SCCs executed + TIA conducted (Schrems II compliant)"
                }
            else:
                return {
                    "compliant": False,
                    "applicable": True,
                    "mechanism": TransferMechanism.SCC,
                    "rationale": "GDPR Article 46: SCCs executed but TIA not conducted (Schrems II violation)"
                }

        # No valid transfer mechanism
        return {
            "compliant": False,
            "applicable": True,
            "mechanism": None,
            "rationale": "GDPR Article 44: No valid transfer mechanism (adequacy, SCC, BCR, or derogation)"
        }

    def _evaluate_dpdpa(self, request: TransferRequest) -> Dict:
        """
        Evaluate DPDPA compliance for cross-border transfer

        DPDPA applies if origin is India or data subjects are Indian residents
        """
        if request.origin_jurisdiction != Jurisdiction.INDIA:
            return {
                "compliant": True,
                "applicable": False,
                "rationale": "DPDPA does not apply (origin not India)"
            }

        dest_country = request.destination_jurisdiction.value

        # DPDPA Section 16: Negative list model (transfers permitted unless restricted)
        if dest_country in self.config.dpdpa_restricted_countries:
            return {
                "compliant": False,
                "applicable": True,
                "rationale": f"DPDPA Section 16(1): {dest_country} is on restricted countries list"
            }

        # Check sectoral restrictions (e.g., RBI for financial data)
        if request.data_category == DataCategory.FINANCIAL_DATA:
            if dest_country in self.config.rbi_restricted_countries:
                return {
                    "compliant": False,
                    "applicable": True,
                    "rationale": f"RBI restriction: {dest_country} not permitted for financial data transfers"
                }

        # DPDPA Rule 6: Security safeguards must travel with the data
        if not request.processor_contract_id:
            return {
                "compliant": False,
                "applicable": True,
                "rationale": "DPDPA Section 8(2) + Rule 6(1)(f): No valid Data Processor contract"
            }

        # DPDPA Section 6: Consent required for processing
        if not request.consent_obtained:
            return {
                "compliant": False,
                "applicable": True,
                "rationale": "DPDPA Section 6(1): No consent obtained for processing"
            }

        # Transfer permitted
        return {
            "compliant": True,
            "applicable": True,
            "rationale": "DPDPA Section 16: Transfer permitted (destination not restricted, safeguards in place)"
        }

    def _make_final_decision(
        self,
        gdpr_result: Dict,
        dpdpa_result: Dict,
        request: TransferRequest
    ) -> Dict:
        """
        Combine GDPR and DPDPA results into final transfer decision
        """
        required_actions = []
        warnings = []

        # Both must be compliant (or not applicable)
        if not gdpr_result["compliant"]:
            required_actions.append(f"GDPR: {gdpr_result['rationale']}")

        if not dpdpa_result["compliant"]:
            required_actions.append(f"DPDPA: {dpdpa_result['rationale']}")

        # High-risk scenarios require manual review
        if request.data_category == DataCategory.SENSITIVE_DATA:
            if self.config.require_manual_review_for_sensitive:
                warnings.append("Sensitive data transfer requires DPO manual review")
                return {
                    "decision": TransferDecision.MANUAL_REVIEW_REQUIRED,
                    "rationale": "Sensitive data category requires manual review",
                    "required_actions": required_actions,
                    "warnings": warnings
                }

        if request.data_volume_records > self.config.high_risk_data_volume_threshold:
            warnings.append(f"High-volume transfer ({request.data_volume_records:,} records) — monitor closely")

        # Make decision
        if gdpr_result["compliant"] and dpdpa_result["compliant"]:
            return {
                "decision": TransferDecision.APPROVED,
                "rationale": "Transfer compliant with both GDPR and DPDPA",
                "required_actions": [],
                "warnings": warnings
            }
        else:
            return {
                "decision": TransferDecision.DENIED,
                "rationale": "Transfer non-compliant with GDPR and/or DPDPA",
                "required_actions": required_actions,
                "warnings": warnings
            }


# =============================================================================
# Example Usage
# =============================================================================

if __name__ == "__main__":
    # Initialize engine
    engine = TransferGovernanceEngine()

    # Example 1: EU → India transfer with SCCs and TIA
    request_eu_india = TransferRequest(
        origin_jurisdiction=Jurisdiction.EU,
        destination_jurisdiction=Jurisdiction.INDIA,
        data_category=DataCategory.PERSONAL_DATA,
        data_volume_records=50000,
        processor_name="Indian SaaS Provider Inc.",
        processor_contract_id="DPA-2026-042",
        scc_executed=True,
        tia_conducted=True,
        consent_obtained=True
    )

    result1 = engine.evaluate_transfer(request_eu_india)
    print(f"\n=== EU → India Transfer ===")
    print(f"Decision: {result1.decision.value}")
    print(f"GDPR Compliant: {result1.gdpr_compliant}")
    print(f"DPDPA Compliant: {result1.dpdpa_compliant}")
    print(f"Rationale: {result1.decision_rationale}")
    if result1.required_actions:
        print(f"Required Actions: {result1.required_actions}")
    if result1.warnings:
        print(f"Warnings: {result1.warnings}")

    # Example 2: India → US transfer (no SCC needed for DPDPA, but US not adequate for GDPR)
    request_india_us = TransferRequest(
        origin_jurisdiction=Jurisdiction.INDIA,
        destination_jurisdiction=Jurisdiction.US,
        data_category=DataCategory.PERSONAL_DATA,
        data_volume_records=10000,
        processor_name="US Cloud Provider Corp.",
        processor_contract_id="DPA-2026-089",
        scc_executed=False,  # Not required for DPDPA-only scenario
        tia_conducted=False,
        consent_obtained=True
    )

    result2 = engine.evaluate_transfer(request_india_us)
    print(f"\n=== India → US Transfer ===")
    print(f"Decision: {result2.decision.value}")
    print(f"GDPR Compliant: {result2.gdpr_compliant}")
    print(f"DPDPA Compliant: {result2.dpdpa_compliant}")
    print(f"Rationale: {result2.decision_rationale}")

    # Example 3: Sensitive data transfer requiring manual review
    request_sensitive = TransferRequest(
        origin_jurisdiction=Jurisdiction.EU,
        destination_jurisdiction=Jurisdiction.INDIA,
        data_category=DataCategory.SENSITIVE_DATA,  # GDPR Article 9 special category
        data_volume_records=1000,
        processor_name="Healthcare Data Processor India",
        processor_contract_id="DPA-2026-150",
        scc_executed=True,
        tia_conducted=True,
        consent_obtained=True
    )

    result3 = engine.evaluate_transfer(request_sensitive)
    print(f"\n=== Sensitive Data Transfer ===")
    print(f"Decision: {result3.decision.value}")
    print(f"Rationale: {result3.decision_rationale}")
    if result3.warnings:
        print(f"Warnings: {result3.warnings}")
