"""Publishing, domain-edge refs, SEO & PWA shells — Phase 11.7.

PublishRelease = publish workflow audit (site/page) beyond simple status flips.
DomainEdgeBinding = DNS/SSL/edge map refs (ADR-009); edge ownership stays Core/Nginx.
SeoMetadata / SitemapShell / RobotsShell = SEO document shells.
PwaManifest = PWA readiness shell (manifest + service-worker ref).
No bundles/feature toggles in this phase.
"""
from __future__ import annotations

import uuid
from datetime import datetime

from sqlalchemy import DateTime, Index, String, Text, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.types import JSON

from app.core.database import Base
from app.models.base import (
    ActorAuditMixin,
    OptimisticLockMixin,
    SoftDeleteMixin,
    TenantMixin,
    TimestampMixin,
    UUIDPrimaryKeyMixin,
)
from app.models.types import (
    GUID,
    DomainEdgeStatus,
    PublishReleaseStatus,
    PublishTarget,
    PwaStatus,
    RobotsStatus,
    SeoStatus,
    SeoTarget,
    SitemapStatus,
)


class PublishRelease(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
    OptimisticLockMixin,
):
    """Publish workflow shell for a site or page."""

    __tablename__ = "experience_publish_releases"

    workspace_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    target_type: Mapped[PublishTarget] = mapped_column(nullable=False)
    target_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    status: Mapped[PublishReleaseStatus] = mapped_column(
        default=PublishReleaseStatus.PENDING, nullable=False
    )
    notes: Mapped[str | None] = mapped_column(Text, nullable=True)
    error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
    completed_at: Mapped[datetime | None] = mapped_column(
        DateTime(timezone=True), nullable=True
    )
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        Index(
            "ix_experience_publish_releases_target",
            "tenant_id",
            "target_type",
            "target_id",
        ),
        Index("ix_experience_publish_releases_status", "tenant_id", "status"),
        Index(
            "ix_experience_publish_releases_tenant_deleted", "tenant_id", "is_deleted"
        ),
    )


class DomainEdgeBinding(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
    OptimisticLockMixin,
):
    """Edge DNS/SSL binding refs for a site domain (ADR-009) — no Nginx ownership."""

    __tablename__ = "experience_domain_edge_bindings"

    workspace_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    site_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    site_domain_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    host: Mapped[str] = mapped_column(String(255), nullable=False)
    status: Mapped[DomainEdgeStatus] = mapped_column(
        default=DomainEdgeStatus.PENDING, nullable=False
    )
    dns_status_ref: Mapped[str | None] = mapped_column(String(255), nullable=True)
    ssl_cert_ref: Mapped[str | None] = mapped_column(String(255), nullable=True)
    edge_map_ref: Mapped[str | None] = mapped_column(String(255), nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id",
            "site_domain_id",
            name="uq_experience_domain_edge_bindings_domain",
        ),
        Index("ix_experience_domain_edge_bindings_site", "tenant_id", "site_id"),
        Index("ix_experience_domain_edge_bindings_host", "tenant_id", "host"),
        Index("ix_experience_domain_edge_bindings_status", "tenant_id", "status"),
        Index(
            "ix_experience_domain_edge_bindings_tenant_deleted",
            "tenant_id",
            "is_deleted",
        ),
    )


class SeoMetadata(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
    OptimisticLockMixin,
):
    """SEO metadata shell for a site or page."""

    __tablename__ = "experience_seo_metadata"

    workspace_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    target_type: Mapped[SeoTarget] = mapped_column(nullable=False)
    target_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    status: Mapped[SeoStatus] = mapped_column(default=SeoStatus.DRAFT, nullable=False)
    title: Mapped[str | None] = mapped_column(String(255), nullable=True)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    canonical_url: Mapped[str | None] = mapped_column(String(500), nullable=True)
    robots_directive: Mapped[str | None] = mapped_column(String(100), nullable=True)
    og_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id",
            "target_type",
            "target_id",
            name="uq_experience_seo_metadata_target",
        ),
        Index("ix_experience_seo_metadata_status", "tenant_id", "status"),
        Index(
            "ix_experience_seo_metadata_tenant_deleted", "tenant_id", "is_deleted"
        ),
    )


class SitemapShell(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
    OptimisticLockMixin,
):
    """Sitemap document shell for a site."""

    __tablename__ = "experience_sitemap_shells"

    workspace_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    site_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    status: Mapped[SitemapStatus] = mapped_column(
        default=SitemapStatus.DRAFT, nullable=False
    )
    entries_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    storage_file_ref: Mapped[str | None] = mapped_column(String(255), nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "site_id", name="uq_experience_sitemap_shells_site"
        ),
        Index("ix_experience_sitemap_shells_status", "tenant_id", "status"),
        Index(
            "ix_experience_sitemap_shells_tenant_deleted", "tenant_id", "is_deleted"
        ),
    )


class RobotsShell(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
    OptimisticLockMixin,
):
    """Robots.txt shell for a site."""

    __tablename__ = "experience_robots_shells"

    workspace_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    site_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    status: Mapped[RobotsStatus] = mapped_column(
        default=RobotsStatus.DRAFT, nullable=False
    )
    content_text: Mapped[str | None] = mapped_column(Text, nullable=True)
    rules_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "site_id", name="uq_experience_robots_shells_site"
        ),
        Index("ix_experience_robots_shells_status", "tenant_id", "status"),
        Index(
            "ix_experience_robots_shells_tenant_deleted", "tenant_id", "is_deleted"
        ),
    )


class PwaManifest(
    Base,
    UUIDPrimaryKeyMixin,
    TenantMixin,
    TimestampMixin,
    SoftDeleteMixin,
    ActorAuditMixin,
    OptimisticLockMixin,
):
    """PWA readiness shell — manifest JSON + service-worker Storage ref."""

    __tablename__ = "experience_pwa_manifests"

    workspace_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    site_id: Mapped[uuid.UUID] = mapped_column(GUID(), nullable=False)
    status: Mapped[PwaStatus] = mapped_column(default=PwaStatus.DRAFT, nullable=False)
    name: Mapped[str | None] = mapped_column(String(255), nullable=True)
    short_name: Mapped[str | None] = mapped_column(String(100), nullable=True)
    start_url: Mapped[str | None] = mapped_column(String(500), nullable=True)
    manifest_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)
    service_worker_ref: Mapped[str | None] = mapped_column(String(255), nullable=True)
    metadata_json: Mapped[dict | None] = mapped_column(JSON, nullable=True)

    __table_args__ = (
        UniqueConstraint(
            "tenant_id", "site_id", name="uq_experience_pwa_manifests_site"
        ),
        Index("ix_experience_pwa_manifests_status", "tenant_id", "status"),
        Index(
            "ix_experience_pwa_manifests_tenant_deleted", "tenant_id", "is_deleted"
        ),
    )
