"""documents 테이블 ORM"""

from datetime import datetime

from pgvector.sqlalchemy import Vector
from sqlalchemy import BigInteger, Boolean, DateTime, Enum, ForeignKey, Integer, String, Text
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import Mapped, mapped_column

# Note: file_type='note' (메모) 문서는 file_path=NULL, file_hash=content SHA-256

from core.database import Base


class Document(Base):
    __tablename__ = "documents"

    id: Mapped[int] = mapped_column(BigInteger, primary_key=True)

    # 1계층: 원본 파일
    file_path: Mapped[str | None] = mapped_column(Text, nullable=True)
    file_hash: Mapped[str] = mapped_column(String(64), nullable=False)
    file_format: Mapped[str] = mapped_column(String(20), nullable=False)
    file_size: Mapped[int | None] = mapped_column(BigInteger)
    file_type: Mapped[str] = mapped_column(
        Enum("immutable", "editable", "note", name="doc_type"),
        default="immutable"
    )
    import_source: Mapped[str | None] = mapped_column(Text)

    # 1계층: 원본명 + 중복검사 (S1-ADD, migration 287)
    # original_filename = 업로드 원본 파일명(다운로드 라벨용). file_path 는 충돌 시 _N 리네임됨.
    #   cf. original_format(ODF 변환용) / original_path·original_hash(007 legacy dead) 와 의미 구분.
    # duplicate_of = canonical doc id (자기 자신이 canonical 이면 NULL). FK ON DELETE SET NULL.
    # duplicate_count = canonical 행에 담는 '본인 제외 동일 판정 사본 수' (group_size-1). 업로드/backfill 가 갱신.
    original_filename: Mapped[str | None] = mapped_column(Text)
    duplicate_of: Mapped[int | None] = mapped_column(
        BigInteger, ForeignKey("documents.id", ondelete="SET NULL")
    )
    duplicate_count: Mapped[int] = mapped_column(
        Integer, nullable=False, default=0, server_default="0"
    )

    # 2계층: 텍스트 추출
    extracted_text: Mapped[str | None] = mapped_column(Text)
    extracted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
    extractor_version: Mapped[str | None] = mapped_column(String(50))

    # 2계층: 추출 메타 (OCR 판정/실행)
    extract_meta: Mapped[dict | None] = mapped_column(JSONB, default=dict)
    ocr_derived: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)

    # 2계층: AI 가공
    ai_summary: Mapped[str | None] = mapped_column(Text)
    ai_tags: Mapped[dict | None] = mapped_column(JSONB, default=[])
    ai_domain: Mapped[str | None] = mapped_column(String(100))
    ai_sub_group: Mapped[str | None] = mapped_column(String(100))
    ai_model_version: Mapped[str | None] = mapped_column(String(50))
    ai_processed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
    document_type: Mapped[str | None] = mapped_column(String(50))
    importance: Mapped[str | None] = mapped_column(String(20), default="medium")
    ai_confidence: Mapped[float | None] = mapped_column()

    # Memo Intake Upgrade PR-2B — Gemma 4B triage 가 추론한 메모 의도 분류 hint
    # ('note' | 'task' | 'calendar_event' | 'activity_log' | 'reference')
    # AI 자동 events 생성 X — 사용자 1-click promote 시점에만 events row 생성 (안전 boundary).
    ai_event_kind: Mapped[str | None] = mapped_column(
        Enum("note", "task", "calendar_event", "activity_log", "reference",
             name="event_kind_hint")
    )
    ai_event_confidence: Mapped[float | None] = mapped_column()

    # 3계층: 벡터 임베딩
    embedding = mapped_column(Vector(1024), nullable=True)
    embed_model_version: Mapped[str | None] = mapped_column(String(50))
    embedded_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))

    # 사용자 메모
    user_note: Mapped[str | None] = mapped_column(Text)

    # 사용자 태그 (ai_tags와 분리, #태그 파싱 결과 또는 수동 입력)
    user_tags: Mapped[list | None] = mapped_column(JSONB, default=[])

    # 핀 고정
    pinned: Mapped[bool] = mapped_column(Boolean, default=False)

    # /ask 합성 포함 여부 (false면 검색은 되지만 evidence에서 제외)
    ask_includable: Mapped[bool] = mapped_column(Boolean, default=True)

    # 아카이브 (현재 메모 UX 전용, 문서 쪽에는 노출하지 않음)
    archived: Mapped[bool] = mapped_column(Boolean, default=False)

    # 메모 체크박스별 메타 — {"<task_index>": {"checked_at": "<ISO8601 UTC>"}}
    # UI에서 체크 후 10초 경과 항목 숨김 판정에 사용. file_type='note'에서만 의미 있음.
    memo_task_state: Mapped[dict] = mapped_column(JSONB, nullable=False, default=dict)

    # ODF 변환
    derived_path: Mapped[str | None] = mapped_column(Text)  # 변환본 경로 (.derived/)
    original_format: Mapped[str | None] = mapped_column(String(20))
    conversion_status: Mapped[str | None] = mapped_column(String(20), default="none")

    # 읽음 상태 (뉴스용)
    is_read: Mapped[bool | None] = mapped_column(Boolean, default=False)

    # 승인/삭제
    review_status: Mapped[str | None] = mapped_column(String(20), default="pending")
    deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))

    # 외부 편집 URL
    edit_url: Mapped[str | None] = mapped_column(Text)

    # 미리보기
    preview_status: Mapped[str | None] = mapped_column(String(20), default="none")
    preview_hash: Mapped[str | None] = mapped_column(String(64))
    preview_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))

    # 메타데이터
    source_channel: Mapped[str | None] = mapped_column(
        Enum("law_monitor", "devonagent", "email", "web_clip",
             "tksafety", "inbox_route", "manual", "drive_sync", "news", "memo",
             "voice", "hermes", "crawl",
             name="source_channel")
    )
    # 외부 채널 (Hermes Discord 등) 의 channel/user/message_id/timestamp 메타.
    # extract_meta (OCR 전용) 와 분리.
    source_metadata: Mapped[dict] = mapped_column(JSONB, nullable=False, default=dict)
    data_origin: Mapped[str | None] = mapped_column(
        Enum("work", "external", name="data_origin")
    )
    # 용도 구분 (우선순위: 수동 수정 > 업로드 명시값 > AI 추론)
    doc_purpose: Mapped[str | None] = mapped_column(
        Enum("business", "knowledge", name="document_purpose")
    )
    title: Mapped[str | None] = mapped_column(Text)

    # 카테고리 (1차 진입점 — UI 탭/라우트 분기)
    # 7 활성: document / library / news / memo / audio / video / law
    # 3 유보: mail / calendar / plex
    category: Mapped[str | None] = mapped_column(
        Enum("document", "library", "news", "memo", "audio", "video", "law",
             "mail", "calendar", "plex",
             name="doc_category", create_type=False)
    )

    # AI 가 제안했지만 미승인된 변경 후보 (category / path / doctype)
    # /accept-suggestion 승인 시에만 category / user_tags 반영 (자동 전이 금지)
    ai_suggestion: Mapped[dict | None] = mapped_column(JSONB)

    # PR-B B-1: summary_triage (4B, 상시) / summary_deep (26B, 에스컬레이션) 분할 산출
    ai_tldr: Mapped[str | None] = mapped_column(Text)                          # ≤60자 TL;DR
    ai_bullets: Mapped[list | None] = mapped_column(JSONB)                     # 3~5개 핵심 bullets
    ai_detail_summary: Mapped[str | None] = mapped_column(Text)                # 26B 2~3문단
    ai_inconsistencies: Mapped[list | None] = mapped_column(JSONB)             # [{kind, desc}]
    # 'triage' | 'deep' | NULL — 현재 문서가 어느 tier 까지 분석 완료됐는지
    ai_analysis_tier: Mapped[str | None] = mapped_column(String(10))

    # 비디오 썸네일 (§3) — ffmpeg 50% 지점 1장. PKM/Videos/.thumbs/{id}.jpg 절대경로.
    thumbnail_path: Mapped[str | None] = mapped_column(Text)

    # NAS 드롭된 mov/mkv/avi quarantine 플래그 (§3). true 면 재생 불가 안내만 표시.
    needs_conversion: Mapped[bool] = mapped_column(Boolean, default=False, server_default="false")

    # facet 탐색 축 (Phase 2)
    facet_company: Mapped[str | None] = mapped_column(Text)
    facet_topic: Mapped[str | None] = mapped_column(Text)
    facet_year: Mapped[int | None] = mapped_column(Integer)
    facet_doctype: Mapped[str | None] = mapped_column(Text)

    # === Phase 1A canonical Markdown layer columns (migrations 211~219) ===
    # plan: ~/.claude/plans/plan-idempotent-sundae.md
    md_content: Mapped[str | None] = mapped_column(Text)
    md_frontmatter: Mapped[dict] = mapped_column(JSONB, nullable=False, default=dict)
    md_format_version: Mapped[str] = mapped_column(Text, nullable=False, default='1.0')
    md_status: Mapped[str] = mapped_column(Text, nullable=False, default='pending')
    md_extraction_engine: Mapped[str | None] = mapped_column(Text)
    md_extraction_engine_version: Mapped[str | None] = mapped_column(Text)
    md_extraction_quality: Mapped[dict | None] = mapped_column(JSONB)
    md_extraction_error: Mapped[str | None] = mapped_column(Text)
    md_content_hash: Mapped[str | None] = mapped_column(Text)
    md_source_hash: Mapped[str | None] = mapped_column(Text)
    md_generated_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
    content_origin: Mapped[str] = mapped_column(Text, nullable=False, default='extracted')
    md_draft_status: Mapped[str | None] = mapped_column(Text)

    # 타임스탬프
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), default=datetime.now
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), default=datetime.now, onupdate=datetime.now
    )
