"""
Lean response schemas for the developer portal public API.
Used when a request authenticates via API key (request.state.auth_method == 'api_key').
These schemas expose only the fields relevant to external integrators.
"""

from datetime import datetime
from typing import Optional, List, Any, Dict


# ─── Helpers ──────────────────────────────────────────────────────────────────

def _v(obj: Any) -> Any:
    """Unwrap enum value if needed."""
    return obj.value if hasattr(obj, "value") else obj


def _d(obj: Any) -> dict:
    """Coerce to dict from Pydantic model, ORM model, or plain dict."""
    if obj is None:
        return {}
    if isinstance(obj, dict):
        return obj
    if hasattr(obj, "model_dump"):
        return obj.model_dump()
    return vars(obj)


# ─── Lean transaction ─────────────────────────────────────────────────────────

def lean_transaction(data: dict) -> dict:
    merchant = _d(data.get("merchant"))
    customer = _d(data.get("customer"))
    pm      = _d(data.get("payment_method"))
    pr      = _d(data.get("payment_request"))

    out: Dict[str, Any] = {
        "id":               data.get("id"),
        "txn_literal":      data.get("txn_literal"),
        "txn_id":           data.get("txn_id"),
        "txn_amount":       data.get("txn_amount"),
        "txn_type":         data.get("txn_type"),
        "txn_status":       _v(data.get("txn_status")),
        "status_text":      data.get("status_text"),
        "currency":         _v(data.get("currency")),
        "description":      data.get("description"),
        "txn_source":       _v(data.get("txn_source")),
        "category":         _v(data.get("category")),
        "charge_type":      data.get("charge_type"),
        "reference_id":     data.get("reference_id"),
        "billing_name":     data.get("billing_name"),
        "refundable_balance": data.get("refundable_balance"),
        "auth_amount":      data.get("auth_amount"),
        "ocurred_at":       data.get("ocurred_at"),
        "merchant":         None,
        "customer":         None,
        "payment_method":   None,
        "payment_request":  None,
        "invoices":         [],
    }

    if merchant:
        out["merchant"] = {
            "id":          merchant.get("id"),
            "merchant_id": merchant.get("merchant_id"),
            "name":        merchant.get("name"),
            "email":       merchant.get("email"),
        }

    if customer:
        out["customer"] = {
            "id":                   customer.get("id"),
            "customer_id":          customer.get("customer_id"),
            "first_name":           customer.get("first_name"),
            "last_name":            customer.get("last_name"),
            "email":                customer.get("email"),
            "phone":                customer.get("phone"),
            "business_legal_name":  customer.get("business_legal_name"),
        }

    if pm:
        card = _d(pm.get("card_details"))
        out["payment_method"] = {
            "id":                pm.get("id"),
            "method":            pm.get("method"),
            "payment_method_id": pm.get("payment_method_id"),
            "card_details": {
                "card_number":   card.get("card_number"),
                "brand":         card.get("brand"),
                "expire_month":  card.get("expire_month"),
                "expire_year":   card.get("expire_year"),
            } if card else None,
        }

    if pr:
        out["payment_request"] = {
            "id":                       pr.get("id"),
            "payment_request_id":       pr.get("payment_request_id"),
            "payment_request_literal":  pr.get("payment_request_literal"),
            "amount":                   pr.get("amount"),
            "status":                   _v(pr.get("status")),
            "payment_frequency":        _v(pr.get("payment_frequency")),
            "authorization_type":       _v(pr.get("authorization_type")),
            "currency":                 _v(pr.get("currency")),
            "due_date":                 pr.get("due_date"),
            "line_items": [
                {
                    "title":       li.get("title"),
                    "description": li.get("description"),
                    "unit_price":  li.get("unit_price"),
                    "quantity":    li.get("quantity"),
                    "tax":         li.get("tax"),
                    "discount":    li.get("discount"),
                }
                for li in (pr.get("line_items") or [])
            ],
        }

    out["invoices"] = [
        {
            "id":               inv.get("id"),
            "invoice_id":       inv.get("invoice_id"),
            "invoice_literal":  inv.get("invoice_literal"),
            "amount":           inv.get("amount"),
            "paid_amount":      inv.get("paid_amount"),
            "status":           _v(inv.get("status")),
            "status_text":      inv.get("status_text"),
            "due_date":         inv.get("due_date"),
            "paid_date":        inv.get("paid_date"),
            "download_url":     inv.get("download_url"),
        }
        for inv in (data.get("invoices") or [])
    ]

    return out


def lean_transaction_list_item(data: dict) -> dict:
    """Minimal fields for a transaction list row."""
    customer = _d(data.get("customer"))
    return {
        "id":           data.get("id"),
        "txn_literal":  data.get("txn_literal"),
        "txn_id":       data.get("txn_id"),
        "txn_amount":   data.get("txn_amount"),
        "txn_type":     data.get("txn_type"),
        "txn_status":   _v(data.get("txn_status")),
        "status_text":  data.get("status_text"),
        "currency":     _v(data.get("currency")),
        "description":  data.get("description"),
        "txn_source":   _v(data.get("txn_source")),
        "category":     _v(data.get("category")),
        "ocurred_at":   data.get("ocurred_at"),
        "customer_name": data.get("customer_name") or (
            " ".join(filter(None, [customer.get("first_name"), customer.get("last_name")]))
            if customer else None
        ),
        "customer_id":  customer.get("customer_id") if customer else None,
    }


# ─── Lean customer ────────────────────────────────────────────────────────────

def lean_customer(data: dict) -> dict:
    default_addr = _d(data.get("default_address"))
    contacts = data.get("contacts") or []

    return {
        "id":                   data.get("id"),
        "customer_id":          data.get("customer_id"),
        "account_literal":      data.get("account_literal"),
        "uin":                  data.get("uin"),
        "first_name":           data.get("first_name"),
        "middle_name":          data.get("middle_name"),
        "last_name":            data.get("last_name"),
        "email":                data.get("email"),
        "phone":                data.get("phone"),
        "business_legal_name":  data.get("business_legal_name"),
        "customer_type":        data.get("customer_type"),
        "account_type":         _v(data.get("account_type")),
        "industry":             data.get("industry"),
        "timezone":             data.get("timezone"),
        "website":              data.get("website"),
        "account_tax_id":       data.get("account_tax_id"),
        "tags":                 data.get("tags_list") or data.get("tags") or [],
        "created_at":           data.get("created_at"),
        "updated_at":           data.get("updated_at"),
        "last_active_date":     data.get("last_active_date"),
        "default_address": {
            "address_line_1": default_addr.get("address_line_1"),
            "address_line_2": default_addr.get("address_line_2"),
            "city":           default_addr.get("city"),
            "state":          default_addr.get("state"),
            "zipcode":        default_addr.get("zipcode"),
            "country":        default_addr.get("country"),
            "address_type":   default_addr.get("address_type"),
        } if default_addr else None,
        "contacts": [
            {
                "id":         c.get("id"),
                "contact_id": c.get("contact_id"),
                "first_name": c.get("first_name"),
                "last_name":  c.get("last_name"),
                "email":      c.get("email"),
                "phone":      c.get("phone"),
                "title":      c.get("title"),
            }
            for c in [_d(c) for c in contacts]
        ],
    }


# ─── Lean payment request ─────────────────────────────────────────────────────

def lean_payment_request(data: dict) -> dict:
    customer = None
    prc_list = data.get("payment_request_customers") or []
    if prc_list:
        first_prc = _d(prc_list[0])
        c = _d(first_prc.get("customer"))
        if c:
            customer = {
                "id":          c.get("id"),
                "customer_id": c.get("customer_id"),
                "first_name":  c.get("first_name"),
                "last_name":   c.get("last_name"),
                "email":       c.get("email"),
                "phone":       c.get("phone"),
            }

    transactions = [
        lean_transaction_list_item(_d(t))
        for t in (data.get("transactions") or [])
    ]

    return {
        "id":                       data.get("id"),
        "payment_request_id":       data.get("payment_request_id"),
        "payment_request_literal":  data.get("payment_request_literal"),
        "amount":                   data.get("amount"),
        "currency":                 _v(data.get("currency")),
        "status":                   _v(data.get("status")),
        "status_text":              data.get("status_text"),
        "payment_frequency":        _v(data.get("payment_frequency")),
        "authorization_type":       _v(data.get("authorization_type")),
        "due_date":                 data.get("due_date"),
        "billing_date":             data.get("billing_date"),
        "created_at":               data.get("created_at"),
        "reference_id":             data.get("reference_id"),
        "message":                  data.get("message"),
        "customer":                 customer,
        "line_items": [
            {
                "id":           li.get("id"),
                "title":        li.get("title"),
                "description":  li.get("description"),
                "unit_price":   li.get("unit_price"),
                "quantity":     li.get("quantity"),
                "tax":          li.get("tax"),
                "discount":     li.get("discount"),
            }
            for li in [_d(li) for li in (data.get("line_items") or [])]
        ],
        "transactions": transactions,
    }


# ─── Lean invoice ─────────────────────────────────────────────────────────────

def lean_invoice(data: dict) -> dict:
    customer = _d(data.get("customer"))
    pr = _d(data.get("payment_request"))

    return {
        "id":               data.get("id"),
        "invoice_id":       data.get("invoice_id"),
        "invoice_literal":  data.get("invoice_literal"),
        "amount":           data.get("amount"),
        "paid_amount":      data.get("paid_amount"),
        "status":           _v(data.get("status")),
        "status_text":      data.get("status_text"),
        "due_date":         data.get("due_date"),
        "paid_date":        data.get("paid_date"),
        "created_at":       data.get("created_at"),
        "download_url":     data.get("download_url"),
        "payment_request_literal": pr.get("payment_request_literal") if pr else None,
        "customer": {
            "id":          customer.get("id"),
            "customer_id": customer.get("customer_id"),
            "first_name":  customer.get("first_name"),
            "last_name":   customer.get("last_name"),
            "email":       customer.get("email"),
        } if customer else None,
        "line_items": [
            {
                "title":        li.get("title"),
                "description":  li.get("description"),
                "unit_price":   li.get("unit_price"),
                "quantity":     li.get("quantity"),
                "tax":          li.get("tax"),
            }
            for li in [_d(li) for li in (data.get("line_items") or [])]
        ],
    }
