"""Endpoint webhook para recibir ventas de pulseras desde Odoo."""
import json
from datetime import datetime, timedelta, date
from fastapi import APIRouter, Depends
from pydantic import BaseModel
from typing import Optional
from sqlalchemy.orm import Session as DBSession
from sqlalchemy import func
from database import get_db
from models import OdooTicket, AuditLog, Session

router = APIRouter(prefix="/api/odoo", tags=["Odoo"])

ODOO_KEY = "shared-secret-key-2026"

MATCH_WINDOW_MINUTES = 10


def _auto_match(db: DBSession, ticket: OdooTicket):
    """Intenta matchear un ticket Odoo con una sesion ICEBERG.

    Criterios:
    - Mismo monto (Session.amount == ticket.total)
    - programmed_at dentro de ±10 min del timestamp del ticket
    - Sesion activa y no matcheada por otro ticket
    - Match unico: exactamente 1 candidata
    """
    ref_time = ticket.odoo_timestamp or ticket.created_at
    if ref_time is None:
        return

    window_start = ref_time - timedelta(minutes=MATCH_WINDOW_MINUTES)
    window_end = ref_time + timedelta(minutes=MATCH_WINDOW_MINUTES)

    # Buscar sesiones candidatas
    candidatas = (
        db.query(Session)
        .filter(
            Session.amount == ticket.total,
            Session.status == 'active',
            Session.programmed_at.isnot(None),
            Session.programmed_at >= window_start,
            Session.programmed_at <= window_end,
        )
        # Excluir sesiones ya matcheadas por otro ticket
        .filter(
            ~Session.id.in_(
                db.query(OdooTicket.matched_session_id)
                .filter(OdooTicket.matched_session_id.isnot(None))
            )
        )
        .all()
    )

    if len(candidatas) == 1:
        session = candidatas[0]
        ticket.matched_session_id = session.id
        ticket.matched_at = datetime.now()

        db.add(AuditLog(
            action='odoo_auto_match',
            session_id=session.id,
            details=json.dumps({
                'ticket_number': ticket.ticket_number,
                'session_id': session.id,
                'amount': ticket.total,
            }),
        ))


class TicketSoldRequest(BaseModel):
    odoo_key: str
    ticket_number: str
    item_name: str
    quantity: int = 1
    unit_price: Optional[float] = None
    total: float
    cashier_name: Optional[str] = None
    cashier_id: Optional[str] = None
    pos_session_id: Optional[str] = None
    timestamp: Optional[str] = None
    venue_id: Optional[str] = None


class TicketSoldResponse(BaseModel):
    status: str
    received_ticket: Optional[str] = None
    message: Optional[str] = None


@router.post("/ticket-sold", response_model=TicketSoldResponse)
def ticket_sold(req: TicketSoldRequest, db: DBSession = Depends(get_db)):
    """
    Webhook: Odoo notifica que se vendio un ticket de pulsera.
    Idempotente — si el ticket ya existe, lo ignora sin error.
    """
    # Validar clave
    if req.odoo_key != ODOO_KEY:
        return TicketSoldResponse(
            status="error",
            message="Clave invalida",
        )

    # Verificar duplicado
    existing = db.query(OdooTicket).filter(
        OdooTicket.ticket_number == req.ticket_number
    ).first()
    if existing:
        return TicketSoldResponse(
            status="ok",
            received_ticket=req.ticket_number,
            message="Ticket ya registrado",
        )

    # Parsear timestamp
    odoo_ts = None
    if req.timestamp:
        try:
            odoo_ts = datetime.fromisoformat(req.timestamp)
        except ValueError:
            pass

    # Insertar ticket
    ticket = OdooTicket(
        ticket_number=req.ticket_number,
        item_name=req.item_name,
        quantity=req.quantity,
        unit_price=req.unit_price,
        total=req.total,
        cashier_name=req.cashier_name,
        cashier_id=req.cashier_id,
        pos_session_id=req.pos_session_id,
        venue_id=req.venue_id,
        odoo_timestamp=odoo_ts,
    )
    db.add(ticket)

    # Auditoria
    db.add(AuditLog(
        action='odoo_ticket_received',
        details=json.dumps({
            'ticket_number': req.ticket_number,
            'item_name': req.item_name,
            'quantity': req.quantity,
            'total': req.total,
            'cashier': req.cashier_name,
            'venue_id': req.venue_id,
        }),
    ))

    # Auto-match con sesion ICEBERG
    db.flush()  # Asegurar que ticket tenga created_at
    _auto_match(db, ticket)

    db.commit()

    print(f"[Odoo] Ticket recibido: {req.ticket_number} - {req.item_name} x{req.quantity} = ${req.total}")

    return TicketSoldResponse(
        status="ok",
        received_ticket=req.ticket_number,
    )


@router.get("/tickets")
def list_tickets(
    fecha: Optional[str] = None,
    venue_id: Optional[str] = None,
    db: DBSession = Depends(get_db),
):
    """Lista tickets de Odoo recibidos. Util para verificacion y debug."""
    q = db.query(OdooTicket)

    if fecha:
        q = q.filter(func.date(OdooTicket.created_at, 'localtime') == fecha)
    else:
        q = q.filter(func.date(OdooTicket.created_at, 'localtime') == date.today())

    if venue_id:
        q = q.filter(OdooTicket.venue_id == venue_id)

    tickets = q.order_by(OdooTicket.created_at.desc()).all()

    return {
        "status": "ok",
        "count": len(tickets),
        "tickets": [
            {
                "ticket_number": t.ticket_number,
                "item_name": t.item_name,
                "quantity": t.quantity,
                "total": t.total,
                "cashier_name": t.cashier_name,
                "venue_id": t.venue_id,
                "timestamp": t.odoo_timestamp.isoformat() if t.odoo_timestamp else None,
                "matched_session_id": t.matched_session_id,
                "received_at": t.created_at.isoformat() if t.created_at else None,
            }
            for t in tickets
        ],
    }


@router.get("/reconciliation")
def reconciliation(
    fecha: Optional[str] = None,
    db: DBSession = Depends(get_db),
):
    """Reporte de cruce Odoo vs ICEBERG del dia.

    - matched: tickets Odoo con sesion ICEBERG matcheada
    - unmatched_odoo: tickets Odoo sin match (venta en Odoo pero pulsera no programada)
    - unmatched_iceberg: sesiones ICEBERG sin match (posible fraude: pulsera sin factura)
    """
    target_date = date.fromisoformat(fecha) if fecha else date.today()

    # Tickets Odoo del dia
    tickets_del_dia = (
        db.query(OdooTicket)
        .filter(func.date(OdooTicket.created_at, 'localtime') == target_date)
        .all()
    )

    matched_tickets = [t for t in tickets_del_dia if t.matched_session_id]
    unmatched_tickets = [t for t in tickets_del_dia if not t.matched_session_id]

    # IDs de sesiones ya matcheadas (del dia)
    matched_session_ids = {t.matched_session_id for t in matched_tickets}

    # Sesiones ICEBERG activas del dia
    sesiones_del_dia = (
        db.query(Session)
        .filter(
            Session.status == 'active',
            Session.programmed_at.isnot(None),
            func.date(Session.programmed_at) == target_date,
        )
        .all()
    )

    unmatched_sessions = [s for s in sesiones_del_dia if s.id not in matched_session_ids]

    return {
        "status": "ok",
        "date": target_date.isoformat(),
        "matched": len(matched_tickets),
        "unmatched_odoo": len(unmatched_tickets),
        "unmatched_iceberg": len(unmatched_sessions),
        "odoo_sin_match": [
            {
                "ticket_number": t.ticket_number,
                "total": t.total,
                "cashier": t.cashier_name,
                "item_name": t.item_name,
                "timestamp": t.odoo_timestamp.isoformat() if t.odoo_timestamp else None,
                "received_at": t.created_at.isoformat() if t.created_at else None,
            }
            for t in unmatched_tickets
        ],
        "iceberg_sin_match": [
            {
                "session_id": s.id,
                "folio": s.folio_number,
                "amount": s.amount,
                "cashier": s.cashier,
                "programmed_at": s.programmed_at.isoformat() if s.programmed_at else None,
            }
            for s in unmatched_sessions
        ],
    }
