# apps/abn_lookup_app/core.py
from typing import Dict, Any
import urllib.request
import urllib.parse
import xml.etree.ElementTree as ET


ABN_LOOKUP_GUID = "cddfe15b-c8e1-4132-bff8-d1501b9c16b9"
ABN_LOOKUP_URL = "https://abr.business.gov.au/abrxmlsearch/AbrXmlSearch.asmx/SearchByABNv202001"


def _fetch_abn_raw(abn: str) -> Dict[str, Any]:
    """
    Consulta directa al servicio ABN Lookup (SearchByABNv202001)
    y devuelve un dict con los datos más importantes en formato 'raw'.

    Si no se encuentra el ABN o hay error, devuelve {}.
    """
    abn = abn.replace(" ", "").strip()

    if not abn.isdigit():
        return {}

    params = {
        "searchString": abn,
        "includeHistoricalDetails": "N",
        "authenticationGuid": ABN_LOOKUP_GUID,
    }

    # La API soporta POST x-www-form-urlencoded (según docs oficiales)
    data = urllib.parse.urlencode(params).encode("utf-8")

    try:
        req = urllib.request.Request(ABN_LOOKUP_URL, data=data)
        with urllib.request.urlopen(req, timeout=10) as response:
            xml_bytes = response.read()
    except Exception:
        # Cualquier error de red / timeout -> sin datos
        return {}

    try:
        root = ET.fromstring(xml_bytes)
    except Exception:
        return {}

    # Helper para leer textos con namespace comodín
    def find_text(path: str) -> str | None:
        """
        Busca un tag usando namespace comodín, por ejemplo:
        ".//{*}identifierValue"
        """
        elem = root.find(path)
        if elem is not None and elem.text:
            return elem.text.strip()
        return None

    # ABN: viene en businessEntity202001/ABN/identifierValue
    abn_value = find_text(".//{*}ABN/{*}identifierValue")
    if not abn_value:
        # Si no hay identifierValue, asumimos que no hubo resultado
        return {}

    # Nombre legal / principal:
    # mainName/organisationName o legalName/fullName en otras variantes
    entity_name = (
        find_text(".//{*}mainName/{*}organisationName")
        or find_text(".//{*}legalName/{*}fullName")
        or find_text(".//{*}businessName/{*}organisationName")
    )

    # Tipo de entidad: entityType/entityDescription o entityTypeCode
    entity_type = (
        find_text(".//{*}entityType/{*}entityDescription")
        or find_text(".//{*}entityType/{*}entityTypeCode")
    )

    # Estado del ABN: entityStatus/entityStatusCode
    status = find_text(".//{*}entityStatus/{*}entityStatusCode")
    status_from = find_text(".//{*}entityStatus/{*}effectiveFrom")

    # Última actualización del registro
    last_updated = find_text(".//{*}recordLastUpdatedDate")

    # Dirección física principal: estado + código postal
    physical_state = find_text(".//{*}mainBusinessPhysicalAddress/{*}stateCode")
    physical_postcode = find_text(".//{*}mainBusinessPhysicalAddress/{*}postcode")
    physical_address = None
    if physical_state or physical_postcode:
        physical_address = " ".join(
            part for part in [physical_state, physical_postcode] if part
        )

    # Dirección postal (si existe)
    postal_state = find_text(".//{*}mainBusinessPostalAddress/{*}stateCode")
    postal_postcode = find_text(".//{*}mainBusinessPostalAddress/{*}postcode")
    postal_address = None
    if postal_state or postal_postcode:
        postal_address = " ".join(
            part for part in [postal_state, postal_postcode] if part
        )

    # GST: en esta versión el ejemplo real trae:
    # <goodsAndServicesTax><effectiveFrom>...</effectiveFrom>...
    gst_effective_from = find_text(".//{*}goodsAndServicesTax/{*}effectiveFrom")
    gst_effective_to = find_text(".//{*}goodsAndServicesTax/{*}effectiveTo")

    gst_registered = bool(gst_effective_from) and (
        (gst_effective_to or "0001-01-01") == "0001-01-01"
    )

    return {
        "abn": abn_value,
        "entity_name": entity_name,
        "entity_type": entity_type,
        "status": status,
        "status_from": status_from,
        "last_updated": last_updated,
        "physical_address": physical_address,
        "postal_address": postal_address,
        "gst": {
            "registered": gst_registered,
            "from": gst_effective_from,
            "to": gst_effective_to,
        },
    }


def lookup_abn_basic(abn: str) -> Dict[str, Any]:
    """
    Versión 0 (básica) del lookup de ABN para Australia.
    Esta es la que usará wp_invoices.
    """
    raw = _fetch_abn_raw(abn)

    if not raw:
        return {
            "service": "abn_lookup",
            "version": 0,
            "country": "AU",
            "tax_id_type": "ABN",
            "tax_id": abn,
            "abn_exists": False,
            "is_active": False,
            "gst_registered": False,
            "entity_name": None,
        }

    status = (raw.get("status") or "").lower()
    gst_info = raw.get("gst") or {}

    return {
        "service": "abn_lookup",
        "version": 0,
        "country": "AU",
        "tax_id_type": "ABN",
        "tax_id": raw.get("abn") or abn,
        "abn_exists": True,
        "is_active": status == "active",
        "gst_registered": bool(gst_info.get("registered")),
        "entity_name": raw.get("entity_name"),
    }


def lookup_abn_full(abn: str) -> Dict[str, Any]:
    """
    Versión 'full' pensada para consola u otras apps (más detalles).
    No la necesita wp_invoices v0, pero la usamos para --full en el CLI.
    """
    raw = _fetch_abn_raw(abn)

    if not raw:
        return {
            "abn_exists": False,
            "abn": abn,
            "entity_name": None,
            "entity_type": None,
            "status": None,
            "status_from": None,
            "last_updated": None,
            "physical_address": None,
            "postal_address": None,
            "gst_registered": False,
            "gst_from": None,
            "gst_to": None,
        }

    gst_info = raw.get("gst") or {}

    return {
        "abn_exists": True,
        "abn": raw.get("abn") or abn,
        "entity_name": raw.get("entity_name"),
        "entity_type": raw.get("entity_type"),
        "status": raw.get("status"),
        "status_from": raw.get("status_from"),
        "last_updated": raw.get("last_updated"),
        "physical_address": raw.get("physical_address"),
        "postal_address": raw.get("postal_address"),
        "gst_registered": bool(gst_info.get("registered")),
        "gst_from": gst_info.get("from"),
        "gst_to": gst_info.get("to"),
    }
