from __future__ import annotations
import uuid
from datetime import datetime
from sqlalchemy import Boolean, DateTime, Integer, String, Text, UniqueConstraint, func
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.types import JSON
from app.core.database import Base
from app.models.base import UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin, ActorAuditMixin
from app.models.types import GUID

class Standard(Base, UUIDPrimaryKeyMixin, TenantMixin, TimestampMixin, ActorAuditMixin):
    __abstract__ = True
    code: Mapped[str | None] = mapped_column(String(120))
    name: Mapped[str | None] = mapped_column(String(255))
    status: Mapped[str] = mapped_column(String(40), default="active", nullable=False)
    data: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)

class PaymentWorkspace(Standard):
    __tablename__="payment_workspaces"
    status: Mapped[str] = mapped_column(String(40), default="enabled", nullable=False)
    default_payment_mode: Mapped[str] = mapped_column(String(40), default="byo_psp", nullable=False)
class PaymentBundleDefinition(Standard): __tablename__="payment_bundle_definitions"
class TenantPaymentBundle(Standard):
    __tablename__="tenant_payment_bundles"
    bundle_code: Mapped[str] = mapped_column(String(120), nullable=False)
    is_active: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
    __table_args__=(UniqueConstraint("tenant_id","bundle_code",name="uq_tenant_bundle"),)
class PaymentFeatureToggle(Standard):
    __tablename__="payment_feature_toggles"
    key: Mapped[str] = mapped_column(String(150), nullable=False)
    enabled: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
class PaymentProviderAssignment(Standard): __tablename__="payment_provider_assignments"
class PspProviderRegistration(Standard):
    __tablename__="psp_provider_registrations"
    provider_code: Mapped[str] = mapped_column(String(80), nullable=False)
class CreditProviderRegistration(Standard):
    __tablename__="credit_provider_registrations"
    provider_code: Mapped[str] = mapped_column(String(80), nullable=False)
class PaymentConfiguration(Standard): __tablename__="payment_configurations"
class PaymentSetting(Standard):
    __tablename__="payment_settings"
    key: Mapped[str] = mapped_column(String(150), nullable=False)
    value: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
class PaymentRole(Standard): __tablename__="payment_roles"
class PaymentPermission(Standard): __tablename__="payment_permissions"
class PaymentAuditLog(Base, UUIDPrimaryKeyMixin, TenantMixin):
    __tablename__="payment_audit_logs"
    entity_type: Mapped[str] = mapped_column(String(100), nullable=False)
    entity_id: Mapped[uuid.UUID | None] = mapped_column(GUID())
    action: Mapped[str] = mapped_column(String(50), nullable=False)
    actor_user_id: Mapped[str | None] = mapped_column(String(100))
    changes: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False)
class OutboxEvent(Base, UUIDPrimaryKeyMixin, TenantMixin):
    __tablename__="outbox_events"
    event_type: Mapped[str] = mapped_column(String(150), nullable=False)
    aggregate_type: Mapped[str] = mapped_column(String(100), nullable=False)
    aggregate_id: Mapped[str] = mapped_column(String(100), nullable=False)
    payload: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
    status: Mapped[str] = mapped_column(String(30), default="pending", nullable=False)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), nullable=False)

class PspConnection(Standard):
    __tablename__="psp_connections"
    provider_code: Mapped[str] = mapped_column(String(80), nullable=False)
    credential_vault_ref: Mapped[str | None] = mapped_column(String(255))
    secret_config: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
class PspCredentialVaultRef(Standard): __tablename__="psp_credential_vault_refs"
class PspConnectionHealthCheck(Standard): __tablename__="psp_connection_health_checks"
class PspRoutingPolicy(Standard): __tablename__="psp_routing_policies"

class MerchantAccount(Standard): __tablename__="merchant_accounts"
class MerchantAccountProfile(Standard): __tablename__="merchant_account_profiles"
class MerchantSettlementProfile(Standard): __tablename__="merchant_settlement_profiles"
class MerchantComplianceRef(Standard): __tablename__="merchant_compliance_refs"
class MerchantAccountStatusHistory(Standard): __tablename__="merchant_account_status_history"

class PaymentRequest(Standard):
    __tablename__="payment_requests"
    status: Mapped[str] = mapped_column(String(40), default="draft", nullable=False)
    idempotency_key: Mapped[str] = mapped_column(String(200), nullable=False)
    amount_minor: Mapped[int] = mapped_column(Integer, nullable=False)
    currency: Mapped[str] = mapped_column(String(3), default="IRR", nullable=False)
    payment_source: Mapped[str] = mapped_column(String(40), default="PSP", nullable=False)
    provider_code: Mapped[str] = mapped_column(String(80), default="mock", nullable=False)
    provider_transaction_id: Mapped[str | None] = mapped_column(String(200))
    redirect_url: Mapped[str | None] = mapped_column(Text)
    source_service: Mapped[str | None] = mapped_column(String(80))
    source_ref_type: Mapped[str | None] = mapped_column(String(80))
    source_ref_id: Mapped[str | None] = mapped_column(String(100))
    credit_provider_id: Mapped[uuid.UUID | None] = mapped_column(GUID())
    financing_reference: Mapped[str | None] = mapped_column(String(200))
    credit_authorization_reference: Mapped[str | None] = mapped_column(String(200))
    installment_contract_reference: Mapped[str | None] = mapped_column(String(200))
    __table_args__=(UniqueConstraint("tenant_id","idempotency_key",name="uq_payment_request_idem"),)
class PaymentRequestStatusHistory(Standard): __tablename__="payment_request_status_history"
class PaymentRequestLine(Standard): __tablename__="payment_request_lines"
class PaymentCallbackLog(Standard):
    __tablename__="payment_callback_logs"
    connection_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    provider_code: Mapped[str] = mapped_column(String(80), nullable=False)
    replay_key: Mapped[str] = mapped_column(String(250), nullable=False)
    __table_args__=(UniqueConstraint("tenant_id","replay_key",name="uq_callback_replay"),)
class PaymentVerificationAttempt(Standard): __tablename__="payment_verification_attempts"
class PaymentTransaction(Standard):
    __tablename__="payment_transactions"
    payment_request_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    amount_minor: Mapped[int] = mapped_column(Integer, nullable=False)
    currency: Mapped[str] = mapped_column(String(3), nullable=False)
    provider_transaction_id: Mapped[str | None] = mapped_column(String(200))
    __table_args__=(UniqueConstraint("tenant_id","payment_request_id",name="uq_transaction_request"),)
class PaymentTransactionFeeLine(Standard): __tablename__="payment_transaction_fee_lines"
class PaymentLedgerEntry(Standard):
    __tablename__="payment_ledger_entries"
    payment_transaction_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    amount_minor: Mapped[int] = mapped_column(Integer, nullable=False)
    direction: Mapped[str] = mapped_column(String(10), nullable=False)
