"""
HPPSession model — audit log for each Hosted Payment Page visit.

One record is written when a customer opens the /initiate endpoint.
submitted_at is stamped when the customer successfully submits payment.
No soft-delete cadence required because this is an immutable audit log;
deleted_at is kept for consistency with the rest of the codebase.
"""

from datetime import datetime
from typing import Optional, TYPE_CHECKING

from sqlalchemy import Boolean, ForeignKey, Index, Integer, String, Text, DateTime
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql import func

from src.apps.base.models.base import Base

if TYPE_CHECKING:
    from src.apps.payment_requests.models.payment_request import PaymentRequest


class HPPSession(Base):
    """
    HPPSession Model: ORM class for the hpp_sessions table.

    Tracks every customer interaction with the Hosted Payment Page for
    compliance, audit, and dispute-evidence purposes.
    """

    __tablename__ = "hpp_sessions"

    __table_args__ = (
        Index("ix_hpp_sessions_payment_request_id", "payment_request_id"),
        Index("ix_hpp_sessions_token", "token"),
    )

    id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True, autoincrement=True)

    # The payment-request this session belongs to.
    payment_request_id: Mapped[int] = mapped_column(
        Integer, ForeignKey("payment_requests.id"), nullable=False
    )

    # The payment-link token the customer arrived with (mirrors
    # payment_requests_links.token for easy cross-reference).
    token: Mapped[str] = mapped_column(String(255), nullable=False)

    # Network / device metadata captured server-side on initiation.
    ip_address: Mapped[Optional[str]] = mapped_column(String(45), nullable=True)   # IPv4 or IPv6
    user_agent: Mapped[Optional[str]] = mapped_column(Text, nullable=True)

    # Merchant HPP settings captured at session creation time.
    display_payer_ip: Mapped[Optional[bool]] = mapped_column(Boolean, nullable=True, default=False)
    display_payer_location: Mapped[Optional[bool]] = mapped_column(Boolean, nullable=True, default=False)

    # MaxMind GeoIP-resolved fields (populated asynchronously; may be null
    # if the GeoIP lookup fails or runs after the record is committed).
    geo_city: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    geo_region: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    geo_country: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    geo_isp: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)

    # Lifecycle timestamps.
    # initiated_at: when the customer first opened the HPP page.
    # submitted_at: stamped when payment is successfully submitted (null until then).
    initiated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), server_default=func.now(), nullable=False
    )
    submitted_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime(timezone=True), nullable=True
    )

    # Soft-delete support (mirrors project convention).
    deleted_at: Mapped[Optional[datetime]] = mapped_column(
        DateTime(timezone=True), nullable=True
    )

    # Relationships
    payment_request: Mapped["PaymentRequest"] = relationship(
        "PaymentRequest", back_populates="hpp_sessions"
    )
