"""Apply LAN sync payloads on the cloud hub database."""
from __future__ import annotations

import logging
from datetime import datetime
from typing import Any, Dict, Optional, Type

from sqlalchemy.orm import Session

from app.models.sales import Sale, SaleItem, Invoice, InvoiceItem, Payment
from app.models.accounting import JournalEntry, JournalTransaction

logger = logging.getLogger(__name__)

ENTITY_MODELS: Dict[str, Type] = {
    "sale": Sale,
    "sale_item": SaleItem,
    "invoice": Invoice,
    "invoice_item": InvoiceItem,
    "payment": Payment,
    "journal_entry": JournalEntry,
    "journal_transaction": JournalTransaction,
}


def _coerce_payload(model_cls: Type, payload: Dict[str, Any]) -> Dict[str, Any]:
    allowed = {c.name for c in model_cls.__table__.columns}
    out: Dict[str, Any] = {}
    for key, value in payload.items():
        if key not in allowed:
            continue
        if value is None:
            out[key] = None
            continue
        col = model_cls.__table__.columns[key]
        col_type = str(col.type).upper()
        if "DATETIME" in col_type or "TIMESTAMP" in col_type:
            if isinstance(value, str):
                try:
                    out[key] = datetime.fromisoformat(value.replace("Z", "+00:00").split("+")[0])
                except ValueError:
                    out[key] = value
            else:
                out[key] = value
        else:
            out[key] = value
    return out


def apply_sync_event(
    db: Session,
    *,
    entity_type: str,
    entity_id: str,
    operation: str,
    payload: Optional[Dict[str, Any]],
    company_id: Optional[str],
) -> tuple[str, Optional[str]]:
    """
    Upsert or delete one entity. Returns (apply_status, error_message).
    company_id is used to stamp company_id on models that have the column when missing.
    """
    model_cls = ENTITY_MODELS.get(entity_type)
    if not model_cls:
        return "skipped", f"Unsupported entity type: {entity_type}"

    if operation == "delete":
        existing = db.query(model_cls).filter(model_cls.id == entity_id).first()
        if existing:
            db.delete(existing)
        return "applied", None

    if not payload:
        return "failed", "Missing payload for upsert"

    data = _coerce_payload(model_cls, payload)
    data["id"] = entity_id
    if company_id and hasattr(model_cls, "company_id") and not data.get("company_id"):
        data["company_id"] = company_id

    existing = db.query(model_cls).filter(model_cls.id == entity_id).first()
    if existing:
        for key, value in data.items():
            if key != "id" and hasattr(existing, key):
                setattr(existing, key, value)
    else:
        db.add(model_cls(**data))

    return "applied", None
