from __future__ import annotations

from datetime import datetime
from typing import Optional
from uuid import UUID, uuid4

import sqlalchemy as sa
from sqlalchemy import ForeignKey, String, Text
from sqlalchemy.dialects.postgresql import JSONB, UUID as PGUUID
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.sql import func
from sqlalchemy.types import DateTime

from src.core.database import Base


class WorkspaceDomain(Base):
    __tablename__ = "workspace_domains"

    id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True, default=uuid4)
    workspace_id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False)
    domain_name: Mapped[str] = mapped_column(String(255), nullable=False)
    normalized_domain: Mapped[str] = mapped_column(String(255), nullable=False)
    domain_type: Mapped[str] = mapped_column(String(30), nullable=False, server_default="external")
    registrar_provider: Mapped[Optional[str]] = mapped_column(String(40), nullable=True)
    registrar_external_id: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    dns_provider: Mapped[Optional[str]] = mapped_column(String(40), nullable=True)
    dns_zone_external_id: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    registration_status: Mapped[str] = mapped_column(String(30), nullable=False, server_default="unmanaged")
    transfer_status: Mapped[str] = mapped_column(String(30), nullable=False, server_default="none")
    verification_status: Mapped[str] = mapped_column(String(30), nullable=False, server_default="pending")
    expires_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
    auto_renew: Mapped[Optional[bool]] = mapped_column(sa.Boolean, nullable=True)
    renewal_authorized: Mapped[bool] = mapped_column(sa.Boolean, nullable=False, server_default=sa.false())
    registrar_lock_status: Mapped[Optional[bool]] = mapped_column(sa.Boolean, nullable=True)
    nameserver_status: Mapped[str] = mapped_column(String(30), nullable=False, server_default="unknown")
    metadata_json: Mapped[dict] = mapped_column(JSONB, nullable=False, server_default=sa.text("'{}'::jsonb"))
    created_by: Mapped[Optional[UUID]] = mapped_column(PGUUID(as_uuid=True), ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
    updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())


class DomainAssignment(Base):
    __tablename__ = "domain_assignments"

    id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True, default=uuid4)
    domain_id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), ForeignKey("workspace_domains.id", ondelete="CASCADE"), nullable=False)
    workspace_id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False)
    project_id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), ForeignKey("projects.id", ondelete="CASCADE"), nullable=False)
    hostname: Mapped[str] = mapped_column(String(255), nullable=False)
    environment: Mapped[str] = mapped_column(String(20), nullable=False, server_default="production")
    assignment_status: Mapped[str] = mapped_column(String(30), nullable=False, server_default="pending")
    dns_status: Mapped[str] = mapped_column(String(30), nullable=False, server_default="pending")
    tls_status: Mapped[str] = mapped_column(String(30), nullable=False, server_default="pending")
    metadata_json: Mapped[dict] = mapped_column(JSONB, nullable=False, server_default=sa.text("'{}'::jsonb"))
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
    updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())


class DomainTransfer(Base):
    __tablename__ = "domain_transfers"
    id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True, default=uuid4)
    domain_id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), ForeignKey("workspace_domains.id", ondelete="CASCADE"), nullable=False)
    workspace_id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False)
    provider: Mapped[str] = mapped_column(String(40), nullable=False)
    provider_transfer_id: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    status: Mapped[str] = mapped_column(String(30), nullable=False, server_default="awaiting_customer_action")
    failure_reason: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    last_checked_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
    completed_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)


class DomainOrder(Base):
    __tablename__ = "domain_orders"
    id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True, default=uuid4)
    workspace_id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False)
    domain_id: Mapped[Optional[UUID]] = mapped_column(PGUUID(as_uuid=True), ForeignKey("workspace_domains.id", ondelete="SET NULL"), nullable=True)
    order_type: Mapped[str] = mapped_column(String(20), nullable=False)
    provider: Mapped[str] = mapped_column(String(40), nullable=False)
    quoted_amount_minor: Mapped[Optional[int]] = mapped_column(sa.Integer, nullable=True)
    charged_amount_minor: Mapped[Optional[int]] = mapped_column(sa.Integer, nullable=True)
    provider_cost_minor: Mapped[Optional[int]] = mapped_column(sa.Integer, nullable=True)
    currency: Mapped[str] = mapped_column(String(3), nullable=False, server_default="USD")
    payment_status: Mapped[str] = mapped_column(String(30), nullable=False, server_default="pending")
    fulfillment_status: Mapped[str] = mapped_column(String(30), nullable=False, server_default="pending")
    idempotency_key: Mapped[str] = mapped_column(String(255), nullable=False)
    stripe_checkout_session_id: Mapped[Optional[str]] = mapped_column(String(100), nullable=True, unique=True)
    stripe_subscription_id: Mapped[Optional[str]] = mapped_column(String(100), nullable=True, unique=True)
    stripe_price_id: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    renewal_failure_count: Mapped[int] = mapped_column(sa.Integer, nullable=False, server_default="0")
    metadata_json: Mapped[dict] = mapped_column(JSONB, nullable=False, server_default=sa.text("'{}'::jsonb"))
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())


class DomainEvent(Base):
    __tablename__ = "domain_events"
    id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True, default=uuid4)
    workspace_id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False)
    domain_id: Mapped[Optional[UUID]] = mapped_column(PGUUID(as_uuid=True), ForeignKey("workspace_domains.id", ondelete="SET NULL"), nullable=True)
    event_type: Mapped[str] = mapped_column(String(60), nullable=False)
    actor_id: Mapped[Optional[UUID]] = mapped_column(PGUUID(as_uuid=True), ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
    payload_json: Mapped[dict] = mapped_column(JSONB, nullable=False, server_default=sa.text("'{}'::jsonb"))
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
