"""Database models for core payment entities.

These ORM models represent the minimum data needed to create and track
payment sessions, audit events, and partner payouts.
"""

import uuid
from datetime import datetime, date
from typing import Optional

from sqlalchemy import Date, DateTime, ForeignKey, Numeric, String, Text
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.types import JSON

from .db import Base


def _uuid() -> str:
    return str(uuid.uuid4())


class Partner(Base):
    """Represents a business partner who receives payments.

    Partners are travel/tour operators who integrate with our checkout
    to accept foreign card payments.
    """

    __tablename__ = "partners"

    id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
    name: Mapped[str] = mapped_column(String(200), nullable=False)
    api_key_hash: Mapped[Optional[str]] = mapped_column(String(255))
    callback_url: Mapped[Optional[str]] = mapped_column(String(500))
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)

    checkout_sessions: Mapped[list["CheckoutSession"]] = relationship(back_populates="partner")
    payouts: Mapped[list["Payout"]] = relationship(back_populates="partner")


class CheckoutSession(Base):
    """Represents a single payment attempt/session.

    Each checkout session is tied to one partner and one external order
    reference, and stores the amount, currency, and current status.
    """

    __tablename__ = "checkout_sessions"

    id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
    partner_id: Mapped[str] = mapped_column(ForeignKey("partners.id"), nullable=False)
    external_order_id: Mapped[str] = mapped_column(String(200), nullable=False)
    amount: Mapped[float] = mapped_column(Numeric(12, 2), nullable=False)
    currency: Mapped[str] = mapped_column(String(3), nullable=False)
    status: Mapped[str] = mapped_column(String(20), default="pending")
    success_url: Mapped[Optional[str]] = mapped_column(String(500))
    cancel_url: Mapped[Optional[str]] = mapped_column(String(500))
    customer_email: Mapped[Optional[str]] = mapped_column(String(320))
    customer_name: Mapped[Optional[str]] = mapped_column(String(200))
    customer_country: Mapped[Optional[str]] = mapped_column(String(2))
    service_type: Mapped[Optional[str]] = mapped_column(String(100))
    channel: Mapped[Optional[str]] = mapped_column(String(50))
    payout_status: Mapped[str] = mapped_column(String(20), default="not_paid")
    payout_method: Mapped[Optional[str]] = mapped_column(String(30))
    payout_batch_id: Mapped[Optional[str]] = mapped_column(String(100))
    payout_paid_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
    consent_analytics: Mapped[bool] = mapped_column(default=False)
    consent_marketing: Mapped[bool] = mapped_column(default=False)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
    updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)

    partner: Mapped["Partner"] = relationship(back_populates="checkout_sessions")
    events: Mapped[list["Event"]] = relationship(back_populates="session")


class Event(Base):
    """Immutable audit log event tied to a checkout session.

    Used for traceability: created, paid, failed, webhook received, etc.
    """

    __tablename__ = "events"

    id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
    session_id: Mapped[str] = mapped_column(ForeignKey("checkout_sessions.id"), nullable=False)
    type: Mapped[str] = mapped_column(String(50), nullable=False)
    provider_event_id: Mapped[Optional[str]] = mapped_column(String(200), unique=True)
    payload: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)

    session: Mapped["CheckoutSession"] = relationship(back_populates="events")


class Payout(Base):
    """Tracks manual or automated payouts to partners.

    MVP supports manual payouts; this model is ready for automation later.
    """

    __tablename__ = "payouts"

    id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
    partner_id: Mapped[str] = mapped_column(ForeignKey("partners.id"), nullable=False)
    period_start: Mapped[Optional[date]] = mapped_column(Date, nullable=True)
    period_end: Mapped[Optional[date]] = mapped_column(Date, nullable=True)
    status: Mapped[str] = mapped_column(String(20), default="not_paid")
    method: Mapped[Optional[str]] = mapped_column(String(30))
    total_amount: Mapped[Optional[float]] = mapped_column(Numeric(12, 2))
    notes: Mapped[Optional[str]] = mapped_column(Text)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)

    partner: Mapped["Partner"] = relationship(back_populates="payouts")
