"""
compliance
==========

Regulatory compliance checks for GST invoices.

This module handles:
- Identifying Composition Dealers (heuristics based on PAN/Entity).
- validating Reverse Charge Mechanism (RCM) applicability.
- B2B (Business-to-Business) vs. Export transaction validation.

Note: Some checks (like definitive Composition status) typically require
real-time API lookups. This module implements structural heuristics
that can be run offline for preliminary validation.

:copyright: (c) 2026
:license: GPL-3.0-only
"""

from typing import Dict
from .gstin import validate as validate_gstin
from .pan import extract_pan_type
from .state import validate_state_code

# --- CONSTANTS ---
_RCM_MANDATORY_SERVICES = [
    "GTA",   # Goods Transport Agency
    "LEGAL", # Legal Services
    "ARB",   # Arbitral Tribunal
]

# Codes often used for "Other Territory" or Special Zones in exports
_EXPORT_STATE_CODES = {"96", "97", "99"}


def is_composition_dealer(gstin: str) -> bool:
    """
    Determines if a GSTIN *might* belong to a Composition Dealer based on structure.

    CRITICAL NOTE:
    --------------
    The GSTIN string itself does *not* strictly encode "Composition" status.
    That is a registration flag in the GSTN database.
    
    However, we can apply negative heuristics:
    1. Certain PAN types (Government 'G', Local Authority 'L') are rarely Composition.
    2. Non-resident taxable persons (foreign PANs) cannot be Composition.
    3. Input Service Distributors (ISD) cannot be Composition.

    Parameters
    ----------
    gstin : str
        The 15-character GSTIN.

    Returns
    -------
    bool
        True if the entity type allows Composition scheme (and thus requires further API check).
        False if the entity type STRICTLY forbids Composition scheme.
    """
    if not validate_gstin(gstin):
        return False

    pan_str = gstin[2:12]
    
    try:
        # Extract the 4th char of PAN (Entity Type)
        pan_type = extract_pan_type(pan_str)
    except ValueError:
        return False

    # List of Entity Types that are generally NOT eligible for Composition Scheme
    # G = Government Agency (Usually TDS Deductor)
    # L = Local Authority
    # T = Trust (Often exempt or regular)
    # C = Company (Can be, but rarely Composition if large turnover)
    
    # Heuristic: We assume valid unless proven ineligible by Entity Type
    # This is a 'permissive' check.
    if pan_type in ["Government Agency", "Local Authority"]:
        return False

    # If the user specifically wants to check Entity Number logic (13th char)
    # High entity codes (e.g., 'Z', '9') often imply multiple registrations,
    # which effectively disqualifies small Composition dealers who usually have 1.
    entity_code = gstin[12]
    if entity_code.isdigit() and int(entity_code) > 3:
        # Heuristic: If you have 4+ registrations in one state, 
        # your turnover likely exceeds the Composition limit (1.5 Cr).
        return False

    return True


def is_reverse_charge_applicable(invoice_data: Dict) -> bool:
    """
    Checks if Reverse Charge Mechanism (RCM) applies to this invoice.
    
    RCM means the BUYER pays the tax, not the Supplier.

    Parameters
    ----------
    invoice_data : dict
        Must contain keys like 'reverse_charge_flag', 'service_type', 
        or 'supplier_gstin'.

    Returns
    -------
    bool
        True if RCM applies.
    """
    # 1. Explicit Flag Check (Common in ERPs like SAP/Tally)
    # Looks for 'Y', 'Yes', 'True', or '1'
    rc_flag = str(invoice_data.get("reverse_charge", "")).lower()
    if rc_flag in ["y", "yes", "true", "1"]:
        return True

    # 2. Service Type Check (GTA, Legal, etc.)
    service_type = invoice_data.get("service_type", "").upper()
    if service_type in _RCM_MANDATORY_SERVICES:
        return True

    # 3. Unregistered Supplier (URD) -> Registered Buyer
    # (Note: This rule has fluctuated in law, but logic remains valid for legacy checks)
    supplier_gstin = invoice_data.get("supplier_gstin")
    buyer_gstin = invoice_data.get("buyer_gstin")

    if buyer_gstin and validate_gstin(buyer_gstin):
        # If supplier has no GSTIN (Unregistered) but Buyer is Registered
        if not supplier_gstin or not validate_gstin(supplier_gstin):
            # Check specific configuration if URD RCM is active for this fiscal year
            if invoice_data.get("enable_urd_rcm", False):
                return True

    return False


def validate_b2b_transaction(buyer_gstin: str) -> bool:
    """
    Validates if a transaction qualifies as B2B (Business-to-Business).
    
    For a transaction to be B2B:
    1. The Buyer MUST have a valid GSTIN.
    2. The Buyer MUST NOT be a consumer (URP - Unregistered Person).

    Parameters
    ----------
    buyer_gstin : str
        The Buyer's GSTIN.

    Returns
    -------
    bool
        True if valid B2B.
    """
    if not buyer_gstin:
        return False
    
    # 1. Standard Validation
    if not validate_gstin(buyer_gstin):
        return False
    
    # 2. Check for UIN (Unique Identity Number)
    # UINs (Foreign Diplomatic Missions, UN Bodies) count as B2B for reporting,
    # even though they don't pay tax in the same way.
    # UIN structure: StateCode + '99' + ... or StateCode + Any + ...
    # We treat valid GSTIN/UIN as B2B.

    return True


def validate_export_gstin(gstin: str) -> bool:
    """
    Validates a GSTIN for Export or Special Economic Zone (SEZ) transactions.

    Exports often involve:
    1. A standard GSTIN (if dealing with an Exporter).
    2. A specific State Code ('96', '97', '99') indicating 'Other Territory'.
    3. Supply to SEZ units (Deemed Export).

    Parameters
    ----------
    gstin : str
        The GSTIN to validate.

    Returns
    -------
    bool
        True if the GSTIN or State Code indicates a valid Export/SEZ entity.
    """
    if not gstin or len(gstin) < 2:
        return False

    state_code = gstin[:2]

    # Check 1: Is it a generic "Foreign/Other" state code?
    if state_code in _EXPORT_STATE_CODES:
        # These codes are explicitly used for imports/exports/high-seas sales
        return True

    # Check 2: If it's a standard GSTIN, is it structurally valid?
    # (An exporter in Maharashtra will have a normal '27' GSTIN)
    if validate_gstin(gstin):
        return True

    return False