"""主案、子方案和共享附件统一文档模型。"""

from __future__ import annotations

from datetime import datetime

from sqlalchemy import (
    BigInteger,
    CheckConstraint,
    ForeignKey,
    Index,
    Integer,
    JSON,
    String,
    Text,
    text,
)
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.dialects import mysql

from dms.database.base import BusinessTableMixin
from dms.extensions import db


class Document(BusinessTableMixin, db.Model):
    __tablename__ = "doc_document"
    __table_args__ = (
        CheckConstraint(
            "document_type IN ('MAIN', 'SUB_PLAN', 'ATTACHMENT')",
            name="document_type",
        ),
        CheckConstraint(
            "document_status IN ('DRAFT', 'PUBLISHED', 'ARCHIVED')",
            name="document_status",
        ),
        CheckConstraint(
            "security_level IN "
            "('PUBLIC', 'INTERNAL', 'SECRET', 'CONFIDENTIAL', 'TOP_SECRET')",
            name="document_security_level",
        ),
        CheckConstraint(
            "visibility_type IN ('ALL_AUTHENTICATED', 'ORGANIZATION', 'CUSTOM')",
            name="document_visibility_type",
        ),
        CheckConstraint(
            "attachment_type IS NULL OR attachment_type IN "
            "('POLICY', 'WORK_STANDARD', 'TABLE', 'DIAGRAM', 'OTHER')",
            name="document_attachment_type",
        ),
        CheckConstraint(
            "content_extract_status IN "
            "('SUCCESS', 'EMPTY', 'UNSUPPORTED', 'FAILED')",
            name="document_content_extract_status",
        ),
        CheckConstraint(
            "("
            "document_type = 'MAIN' "
            "AND parent_document_id IS NULL "
            "AND category_id IS NOT NULL "
            "AND attachment_type IS NULL"
            ") OR ("
            "document_type = 'SUB_PLAN' "
            "AND parent_document_id IS NOT NULL "
            "AND root_document_id IS NOT NULL "
            "AND category_id IS NOT NULL "
            "AND attachment_type IS NULL"
            ") OR ("
            "document_type = 'ATTACHMENT' "
            "AND parent_document_id IS NULL "
            "AND root_document_id IS NULL "
            "AND category_id IS NULL "
            "AND attachment_type IS NOT NULL "
            "AND security_level = 'PUBLIC' "
            "AND visibility_type = 'ALL_AUTHENTICATED'"
            ")",
            name="document_type_shape",
        ),
        Index(
            "ix_doc_document_type_active_updated",
            "document_type",
            "is_deleted",
            "updated_at",
        ),
        Index(
            "ix_doc_document_parent_type_active",
            "parent_document_id",
            "document_type",
            "is_deleted",
        ),
        Index(
            "ix_doc_document_root_active",
            "root_document_id",
            "is_deleted",
        ),
        Index(
            "ix_doc_document_category_active",
            "category_id",
            "is_deleted",
        ),
        Index(
            "ix_doc_document_status_active",
            "document_status",
            "is_deleted",
        ),
        Index(
            "ix_doc_document_security_active",
            "security_level",
            "is_deleted",
        ),
        Index("ix_doc_document_file_hash", "file_hash"),
        Index(
            "ix_doc_document_creator_active",
            "created_by",
            "is_deleted",
        ),
        Index(
            "ix_doc_document_attachment_type_active_updated",
            "attachment_type",
            "is_deleted",
            "updated_at",
        ),
        Index(
            "ix_doc_document_file_extension_active_updated",
            "file_extension",
            "is_deleted",
            "updated_at",
        ),
        Index(
            "ix_doc_document_recycle_deleted",
            "is_deleted",
            "deleted_at",
            "id",
        ),
    )

    document_name: Mapped[str] = mapped_column(String(255), nullable=False)
    summary: Mapped[str | None] = mapped_column(Text, nullable=True)
    document_type: Mapped[str] = mapped_column(String(32), nullable=False)
    document_status: Mapped[str] = mapped_column(
        String(32),
        nullable=False,
        server_default=text("'DRAFT'"),
    )
    security_level: Mapped[str] = mapped_column(
        String(32),
        nullable=False,
        server_default=text("'INTERNAL'"),
    )
    visibility_type: Mapped[str] = mapped_column(
        String(32),
        nullable=False,
        server_default=text("'CUSTOM'"),
    )
    attachment_type: Mapped[str | None] = mapped_column(String(32), nullable=True)
    category_id: Mapped[int | None] = mapped_column(
        BigInteger,
        ForeignKey("doc_category.id", ondelete="RESTRICT"),
        nullable=True,
    )
    category_name: Mapped[str | None] = mapped_column(String(128), nullable=True)
    category_path: Mapped[str | None] = mapped_column(String(1000), nullable=True)
    parent_document_id: Mapped[int | None] = mapped_column(
        BigInteger,
        ForeignKey("doc_document.id", ondelete="RESTRICT"),
        nullable=True,
    )
    root_document_id: Mapped[int | None] = mapped_column(
        BigInteger,
        ForeignKey("doc_document.id", ondelete="RESTRICT"),
        nullable=True,
    )
    tags: Mapped[list[str] | None] = mapped_column(JSON, nullable=True)
    original_file_name: Mapped[str] = mapped_column(String(255), nullable=False)
    file_relative_path: Mapped[str] = mapped_column(String(1000), nullable=False)
    file_extension: Mapped[str] = mapped_column(String(20), nullable=False)
    mime_type: Mapped[str | None] = mapped_column(String(128), nullable=True)
    file_size: Mapped[int] = mapped_column(
        BigInteger,
        nullable=False,
        server_default=text("0"),
    )
    file_hash: Mapped[str] = mapped_column(String(64), nullable=False)
    child_count: Mapped[int] = mapped_column(
        Integer,
        nullable=False,
        server_default=text("0"),
    )
    attachment_count: Mapped[int] = mapped_column(
        Integer,
        nullable=False,
        server_default=text("0"),
    )
    view_count: Mapped[int] = mapped_column(
        BigInteger,
        nullable=False,
        server_default=text("0"),
    )
    download_count: Mapped[int] = mapped_column(
        BigInteger,
        nullable=False,
        server_default=text("0"),
    )
    search_text: Mapped[str | None] = mapped_column(mysql.LONGTEXT, nullable=True)
    content_text: Mapped[str | None] = mapped_column(mysql.LONGTEXT, nullable=True)
    content_extract_status: Mapped[str] = mapped_column(
        String(32),
        nullable=False,
        server_default=text("'UNSUPPORTED'"),
    )
    content_extracted_at: Mapped[datetime | None] = mapped_column(
        mysql.DATETIME(fsp=3),
        nullable=True,
    )
    created_by_name: Mapped[str | None] = mapped_column(String(64), nullable=True)
    updated_by_name: Mapped[str | None] = mapped_column(String(64), nullable=True)
