"""
EU VAT validation and Stripe reverse-charge integration for ModuleDesk.

Seller is Spain-based (ES); customers are EU B2B. Validated VAT IDs result in:
  - 0% reverse-charge treatment via Stripe tax IDs
  - Invoice footer citing Art. 196 Council Directive 2006/112/EC

VIES reliability: the EU VIES REST API is frequently unavailable. Any network
error, timeout, or 5xx response is treated as 'unavailable' — the number is
stored with vat_validated=False and signup is never blocked. Validation can be
retried later (e.g. from the billing page).
"""

from __future__ import annotations

import logging
import re
from typing import Optional

logger = logging.getLogger(__name__)

VIES_URL = "https://ec.europa.eu/taxation_customs/vies/rest-api/check-vat-number"
VIES_TIMEOUT = 6  # seconds — VIES is slow; short enough not to block UX

# EU country codes for basic sanity check
EU_COUNTRY_CODES = {
    "AT", "BE", "BG", "CY", "CZ", "DE", "DK", "EE", "EL", "ES", "FI", "FR",
    "HR", "HU", "IE", "IT", "LT", "LU", "LV", "MT", "NL", "PL", "PT", "RO",
    "SE", "SI", "SK",
}

STRIPE_VAT_INVOICE_FOOTER = (
    "VAT reverse charge — Art. 196 Council Directive 2006/112/EC"
)


def normalize_vat(raw: str) -> Optional[str]:
    """
    Normalize a raw VAT ID string.

    Strips spaces, converts to uppercase, removes non-alphanumeric separators.
    Returns None if the string is clearly not a VAT ID (too short, no country code).
    """
    if not raw:
        return None
    # Remove all spaces and dashes
    cleaned = re.sub(r"[\s\-\.]", "", raw.strip().upper())
    # Must start with 2 alpha chars (country code)
    if len(cleaned) < 4 or not cleaned[:2].isalpha():
        return None
    return cleaned


def split_vat(normalized: str) -> tuple[str, str]:
    """Split a normalized VAT ID into (country_code, vat_number_body)."""
    return normalized[:2], normalized[2:]


def validate_vat(raw_vat: str) -> dict:
    """
    Validate an EU VAT number via the VIES REST API.

    Returns a dict with keys:
      - status: 'valid' | 'invalid' | 'unavailable'
      - normalized: the normalized VAT string (or None)
      - name: business name from VIES (if valid)
      - address: business address from VIES (if valid)
      - detail: human-readable explanation

    Graceful degradation: on any network error, timeout, or VIES 5xx,
    returns status='unavailable'. Callers must NOT block signup on this.
    """
    normalized = normalize_vat(raw_vat)
    if not normalized:
        return {
            "status": "invalid",
            "normalized": None,
            "name": None,
            "address": None,
            "detail": "VAT number format is invalid.",
        }

    country_code, vat_body = split_vat(normalized)

    # Basic EU membership check (note: GR is represented as EL in VAT)
    if country_code not in EU_COUNTRY_CODES:
        return {
            "status": "invalid",
            "normalized": normalized,
            "name": None,
            "address": None,
            "detail": f"'{country_code}' is not a recognized EU VAT country code.",
        }

    try:
        import requests
        resp = requests.post(
            VIES_URL,
            json={"countryCode": country_code, "vatNumber": vat_body},
            timeout=VIES_TIMEOUT,
            headers={"Accept": "application/json"},
        )

        if resp.status_code == 200:
            data = resp.json()
            is_valid = data.get("isValid", False)
            name = data.get("name") or None
            address = data.get("address") or None

            if is_valid:
                return {
                    "status": "valid",
                    "normalized": normalized,
                    "name": name,
                    "address": address,
                    "detail": "VAT number verified via VIES.",
                }
            else:
                return {
                    "status": "invalid",
                    "normalized": normalized,
                    "name": None,
                    "address": None,
                    "detail": "VIES reports this VAT number as invalid.",
                }

        # VIES returned a non-200 — treat as unavailable (do not block)
        logger.warning("VIES returned HTTP %s for %s", resp.status_code, normalized)
        return {
            "status": "unavailable",
            "normalized": normalized,
            "name": None,
            "address": None,
            "detail": "VIES could not be reached — the number will be re-validated later.",
        }

    except Exception as exc:
        logger.warning("VIES validation error for %s: %s", normalized, exc)
        return {
            "status": "unavailable",
            "normalized": normalized,
            "name": None,
            "address": None,
            "detail": "VIES is temporarily unavailable — your number has been saved and will be re-validated.",
        }


def push_vat_to_stripe(org) -> bool:
    """
    Push the org's validated VAT number to Stripe as a tax ID on the customer.

    Also sets the customer's invoice_settings.footer to the reverse-charge
    legal notice when the VAT is validated, or clears it if removed.

    Returns True on success or if there is nothing to do (no Stripe customer
    or no STRIPE_SECRET_KEY configured). Returns False only on Stripe API error.

    Call this after create_stripe_customer() has run and after storing a new
    vat_number on the org.
    """
    import os
    stripe_key = os.getenv("STRIPE_SECRET_KEY")
    if not stripe_key:
        logger.debug("push_vat_to_stripe: STRIPE_SECRET_KEY not set — skipping")
        return True  # graceful degradation

    if not org.stripe_customer_id:
        logger.debug(
            "push_vat_to_stripe: org %s has no Stripe customer yet — skipping", org.id
        )
        return True

    try:
        import stripe as _stripe
        _stripe.api_key = stripe_key

        # Determine footer and tax ID based on current org state
        has_validated_vat = bool(org.vat_number and org.vat_validated)
        footer = STRIPE_VAT_INVOICE_FOOTER if has_validated_vat else ""

        # Update customer invoice footer
        _stripe.Customer.modify(
            org.stripe_customer_id,
            invoice_settings={"footer": footer},
        )

        if has_validated_vat:
            # Add tax ID — Stripe de-dupes by type+value so this is safe to call
            # repeatedly. We ignore "already exists" errors.
            normalized = normalize_vat(org.vat_number)
            if normalized:
                try:
                    _stripe.Customer.create_tax_id(
                        org.stripe_customer_id,
                        type="eu_vat",
                        value=normalized,
                    )
                    logger.info(
                        "Added Stripe tax ID eu_vat=%s to customer %s (org %s)",
                        normalized, org.stripe_customer_id, org.id,
                    )
                except _stripe.error.InvalidRequestError as e:
                    # 'Tax ID already exists' is fine; re-raise others
                    if "already exists" not in str(e).lower():
                        raise

        logger.info(
            "push_vat_to_stripe: updated customer %s for org %s (validated=%s, footer=%r)",
            org.stripe_customer_id, org.id, has_validated_vat, footer,
        )
        return True

    except Exception as exc:
        logger.error(
            "push_vat_to_stripe failed for org %s (customer %s): %s",
            org.id, org.stripe_customer_id, exc,
        )
        return False


def save_vat_on_org(org, raw_vat: str) -> dict:
    """
    Convenience: normalize, validate via VIES, update org fields in place.

    The caller must be inside a session_scope() with `org` already attached
    so that changes to `org.vat_number` / `org.vat_validated` are committed
    by the caller's session.

    Returns the validation result dict from validate_vat().
    """
    if not raw_vat or not raw_vat.strip():
        # Empty field — clear VAT
        org.vat_number = None
        org.vat_validated = False
        return {"status": "cleared", "normalized": None, "detail": "VAT number removed."}

    result = validate_vat(raw_vat)
    normalized = result.get("normalized") or normalize_vat(raw_vat)

    org.vat_number = normalized
    org.vat_validated = result["status"] == "valid"

    return result
