"""
validators
==========

The User-Facing API.

This module aggregates logic from gstin, pan, state, and invoice modules
into simple, rich-response functions. Use this for your main application logic.

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

from typing import Dict, Any

# Import all our internal modules
from . import gstin, pan, state, invoice, compliance

def validate_gstin(gstin_input: str) -> Dict[str, Any]:
    """
    Performs a comprehensive check on a single GSTIN.
    
    Returns a rich dictionary containing all metadata (State, PAN type, etc.)
    or error details if invalid.

    Parameters
    ----------
    gstin_input : str
        The GSTIN string to check.

    Returns
    -------
    dict
        {
            "valid": bool,
            "gstin": str,
            "state": str,
            "pan": str,
            "entity_type": str,
            "is_composition": bool,
            "errors": list
        }
    """
    response = {
        "valid": False,
        "gstin": gstin_input,
        "state": None,
        "pan": None,
        "entity_type": None,
        "checksum_valid": False,
        "errors": []
    }

    # 1. Basic Format & Checksum Validation
    if not gstin.validate(gstin_input):
        response["errors"].append("Invalid Format or Checksum")
        # Even if invalid, we try to extract partial data if length allows
        if not gstin_input or len(gstin_input) < 15:
            return response
    else:
        response["valid"] = True
        response["checksum_valid"] = True

    # 2. Extract Metadata
    meta = gstin.get_metadata(gstin_input)
    
    # 3. Enrich with State Name
    st_code = meta.get("state_code")
    response["state"] = state.get_state_name_from_code(st_code)

    # 4. Enrich with PAN Data
    pan_str = meta.get("pan")
    response["pan"] = pan_str
    if pan_str:
        try:
            response["entity_type"] = pan.extract_pan_type(pan_str)
        except ValueError:
            response["errors"].append("Invalid PAN structure embedded in GSTIN")

    # 5. Check Composition Status (Heuristic)
    response["is_composition"] = compliance.is_composition_dealer(gstin_input)

    return response


def validate_invoice(invoice_data: Dict[str, Any]) -> Dict[str, Any]:
    """
    Validates an entire invoice object for cross-field consistency.

    Parameters
    ----------
    invoice_data : dict
        Expected keys:
        - supplier_gstin (str)
        - buyer_gstin (str)
        - place_of_supply (str, 2-digit code)
        - tax_amounts (dict: {'cgst': 0.0, 'sgst': 0.0, 'igst': 0.0})

    Returns
    -------
    dict
        {
            "valid": bool,
            "transaction_type": str,
            "errors": list
        }
    """
    response = {
        "valid": True,
        "transaction_type": None,
        "errors": []
    }

    supplier = invoice_data.get("supplier_gstin")
    buyer = invoice_data.get("buyer_gstin")
    pos = invoice_data.get("place_of_supply")
    tax_data = invoice_data.get("tax_amounts", {})

    # 1. Validate GSTINs
    if not invoice.validate_supplier_and_buyer_gstin(supplier, buyer):
        response["valid"] = False
        response["errors"].append("Invalid Supplier or Buyer GSTIN (or they are identical)")
        return response

    # 2. Determine Transaction Type (Inter vs Intra)
    txn_type = invoice.determine_transaction_type(supplier, buyer)
    response["transaction_type"] = txn_type

    # 3. Validate Place of Supply (POS) Logic
    # POS Code should match Buyer State (usually) or the destination logic.
    # Here we check if Supplier State vs POS matches the Transaction Type.
    is_intra = state.validate_place_of_supply(supplier, pos)
    
    if is_intra and txn_type == "INTER_STATE":
        response["valid"] = False
        response["errors"].append(
            f"Mismatch: GSTINs imply Inter-state, but Place of Supply ({pos}) implies Intra-state."
        )

    # 4. Validate Tax Structure (CGST/SGST vs IGST)
    if not invoice.validate_tax_structure(txn_type, tax_data):
        response["valid"] = False
        response["errors"].append(
            f"Tax Mismatch: Transaction is {txn_type} but tax amounts {tax_data} do not match rules."
        )
    
    # 5. Check Regulatory Compliance (B2B checks)
    if not compliance.validate_b2b_transaction(buyer):
        response["errors"].append("Buyer GSTIN invalid for B2B transaction")
        # We don't fail validation here strictly, just warn, unless strict mode is on.

    return response