"""
Home 모듈 SQLAlchemy 모델 정의

이 모듈은 영상 제작 파이프라인의 핵심 데이터 모델을 정의합니다.
- Project: 프로젝트(사용자 입력 이력) 관리
- Image: 업로드된 이미지 URL 관리
- UserProject: User와 Project 간 M:N 관계 중계 테이블
"""

from datetime import datetime
from typing import TYPE_CHECKING, List, Optional

from sqlalchemy import BigInteger, DateTime, ForeignKey, Index, Integer, String, Text, func
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.database.session import Base

if TYPE_CHECKING:
    from app.lyric.models import Lyric
    from app.song.models import Song
    from app.user.models import User
    from app.video.models import Video

# =============================================================================
# User-Project M:N 관계 중계 테이블
# =============================================================================
#
# 설계 의도:
#   - User와 Project는 다대다(M:N) 관계입니다.
#   - 한 사용자는 여러 프로젝트에 참여할 수 있습니다.
#   - 한 프로젝트에는 여러 사용자가 참여할 수 있습니다.
#
# 중계 테이블 역할:
#   - UserProject 테이블이 두 테이블 간의 관계를 연결합니다.
#   - 각 레코드는 특정 사용자와 특정 프로젝트의 연결을 나타냅니다.
#   - 추가 속성(role, joined_at)으로 관계의 메타데이터를 저장합니다.
#
# 외래키 설정:
#   - user_id: User 테이블의 id를 참조 (ON DELETE CASCADE)
#   - project_id: Project 테이블의 id를 참조 (ON DELETE CASCADE)
#   - CASCADE 설정으로 부모 레코드 삭제 시 중계 레코드도 자동 삭제됩니다.
#
# 관계 방향:
#   - User.projects → UserProject → Project (사용자가 참여한 프로젝트 목록)
#   - Project.users → UserProject → User (프로젝트에 참여한 사용자 목록)
# =============================================================================


class UserProject(Base):
    """
    User-Project M:N 관계 중계 테이블

    사용자와 프로젝트 간의 다대다 관계를 관리합니다.
    한 사용자는 여러 프로젝트에 참여할 수 있고,
    한 프로젝트에는 여러 사용자가 참여할 수 있습니다.

    Attributes:
        id: 고유 식별자 (자동 증가)
        user_id: 사용자 외래키 (User.id 참조)
        project_id: 프로젝트 외래키 (Project.id 참조)
        role: 프로젝트 내 사용자 역할 (owner: 소유자, member: 멤버, viewer: 조회자)
        joined_at: 프로젝트 참여 일시

    외래키 제약조건:
        - user_id → user.id (ON DELETE CASCADE)
        - project_id → project.id (ON DELETE CASCADE)

    유니크 제약조건:
        - (user_id, project_id) 조합은 유일해야 함 (중복 참여 방지)
    """

    __tablename__ = "user_project"
    __table_args__ = (
        Index("idx_user_project_user_id", "user_id"),
        Index("idx_user_project_project_id", "project_id"),
        Index("idx_user_project_user_project", "user_id", "project_id", unique=True),
        {
            "mysql_engine": "InnoDB",
            "mysql_charset": "utf8mb4",
            "mysql_collate": "utf8mb4_unicode_ci",
        },
    )

    id: Mapped[int] = mapped_column(
        Integer,
        primary_key=True,
        nullable=False,
        autoincrement=True,
        comment="고유 식별자",
    )

    # 외래키: User 테이블 참조
    # - BigInteger 사용 (User.id가 BigInteger이므로 타입 일치 필요)
    # - ondelete="CASCADE": User 삭제 시 연결된 UserProject 레코드도 삭제
    user_id: Mapped[int] = mapped_column(
        BigInteger,
        ForeignKey("user.id", ondelete="CASCADE"),
        nullable=False,
        comment="사용자 외래키 (User.id 참조)",
    )

    # 외래키: Project 테이블 참조
    # - Integer 사용 (Project.id가 Integer이므로 타입 일치 필요)
    # - ondelete="CASCADE": Project 삭제 시 연결된 UserProject 레코드도 삭제
    project_id: Mapped[int] = mapped_column(
        Integer,
        ForeignKey("project.id", ondelete="CASCADE"),
        nullable=False,
        comment="프로젝트 외래키 (Project.id 참조)",
    )

    # ==========================================================================
    # Relationships (관계 설정)
    # ==========================================================================
    # back_populates: 양방향 관계 설정 (User.user_projects, Project.user_projects)
    # lazy="selectin": N+1 문제 방지를 위한 즉시 로딩
    # ==========================================================================
    user: Mapped["User"] = relationship(
        "User",
        back_populates="user_projects",
        lazy="selectin",
    )

    project: Mapped["Project"] = relationship(
        "Project",
        back_populates="user_projects",
        lazy="selectin",
    )

    def __repr__(self) -> str:
        return (
            f"<UserProject("
            f"id={self.id}, "
            f"user_id={self.user_id}, "
            f"project_id={self.project_id}, "
            f"role='{self.role}'"
            f")>"
        )


class Project(Base):
    """
    프로젝트 테이블 (사용자 입력 이력)

    영상 제작 요청의 시작점으로, 고객 정보와 지역 정보를 저장합니다.
    하위 테이블(Lyric, Song, Video)의 부모 테이블 역할을 합니다.

    Attributes:
        id: 고유 식별자 (자동 증가)
        store_name: 고객명 (필수)
        region: 지역명 (필수, 예: 서울, 부산, 대구 등)
        task_id: 작업 고유 식별자 (UUID 형식, 36자)
        detail_region_info: 상세 지역 정보 (선택, JSON 또는 텍스트 형식)
        created_at: 생성 일시 (자동 설정)

    Relationships:
        lyrics: 생성된 가사 목록
        songs: 생성된 노래 목록
        videos: 최종 영상 결과 목록
        user_projects: User와의 M:N 관계 (중계 테이블 통한 연결)
        users: 프로젝트에 참여한 사용자 목록 (Association Proxy)
    """

    __tablename__ = "project"
    __table_args__ = (
        Index("idx_project_task_id", "task_id"),
        Index("idx_project_store_name", "store_name"),
        Index("idx_project_region", "region"),
        {
            "mysql_engine": "InnoDB",
            "mysql_charset": "utf8mb4",
            "mysql_collate": "utf8mb4_unicode_ci",
        },
    )

    id: Mapped[int] = mapped_column(
        Integer,
        primary_key=True,
        nullable=False,
        autoincrement=True,
        comment="고유 식별자",
    )

    store_name: Mapped[str] = mapped_column(
        String(255),
        nullable=False,
        index=True,
        comment="가게명",
    )

    region: Mapped[str] = mapped_column(
        String(100),
        nullable=False,
        index=True,
        comment="지역명 (예: 군산)",
    )

    task_id: Mapped[str] = mapped_column(
        String(36),
        nullable=False,
        comment="프로젝트 작업 고유 식별자 (UUID)",
    )

    detail_region_info: Mapped[Optional[str]] = mapped_column(
        Text,
        nullable=True,
        comment="상세 지역 정보",
    )

    language: Mapped[str] = mapped_column(
        String(50),
        nullable=False,
        default="Korean",
        comment="출력 언어 (Korean, English, Chinese, Japanese, Thai, Vietnamese)",
    )

    created_at: Mapped[datetime] = mapped_column(
        DateTime,
        nullable=False,
        server_default=func.now(),
        comment="생성 일시",
    )

    # Relationships
    lyrics: Mapped[List["Lyric"]] = relationship(
        "Lyric",
        back_populates="project",
        cascade="all, delete-orphan",
        lazy="selectin",
    )

    songs: Mapped[List["Song"]] = relationship(
        "Song",
        back_populates="project",
        cascade="all, delete-orphan",
        lazy="selectin",
    )

    videos: Mapped[List["Video"]] = relationship(
        "Video",
        back_populates="project",
        cascade="all, delete-orphan",
        lazy="selectin",
    )

    # ==========================================================================
    # User M:N 관계 (중계 테이블 UserProject 통한 연결)
    # ==========================================================================
    # back_populates: UserProject.project와 양방향 연결
    # cascade: Project 삭제 시 UserProject 레코드도 삭제 (User는 유지)
    # lazy="selectin": N+1 문제 방지
    # ==========================================================================
    user_projects: Mapped[List["UserProject"]] = relationship(
        "UserProject",
        back_populates="project",
        cascade="all, delete-orphan",
        lazy="selectin",
    )

    def __repr__(self) -> str:
        def truncate(value: str | None, max_len: int = 10) -> str:
            if value is None:
                return "None"
            return (value[:max_len] + "...") if len(value) > max_len else value

        return (
            f"<Project("
            f"id={self.id}, "
            f"store_name='{self.store_name}', "
            f"task_id='{truncate(self.task_id)}'"
            f")>"
        )


class Image(Base):
    """
    업로드 이미지 테이블

    사용자가 업로드한 이미지의 URL을 저장합니다.
    독립적으로 관리되며 Project와 직접적인 관계가 없습니다.

    Attributes:
        id: 고유 식별자 (자동 증가)
        task_id: 이미지 업로드 작업 고유 식별자 (UUID)
        img_name: 이미지명
        img_url: 이미지 URL (S3, CDN 등의 경로)
        created_at: 생성 일시 (자동 설정)
    """

    __tablename__ = "image"
    __table_args__ = (
        {
            "mysql_engine": "InnoDB",
            "mysql_charset": "utf8mb4",
            "mysql_collate": "utf8mb4_unicode_ci",
        },
    )

    id: Mapped[int] = mapped_column(
        Integer,
        primary_key=True,
        nullable=False,
        autoincrement=True,
        comment="고유 식별자",
    )

    task_id: Mapped[str] = mapped_column(
        String(36),
        nullable=False,
        comment="이미지 업로드 작업 고유 식별자 (UUID)",
    )

    img_name: Mapped[str] = mapped_column(
        String(255),
        nullable=False,
        comment="이미지명",
    )

    img_url: Mapped[str] = mapped_column(
        String(2048),
        nullable=False,
        comment="이미지 URL (blob, CDN 경로)",
    )

    img_order: Mapped[int] = mapped_column(
        Integer,
        nullable=False,
        default=0,
        comment="이미지 순서",
    )

    created_at: Mapped[datetime] = mapped_column(
        DateTime,
        nullable=False,
        server_default=func.now(),
        comment="생성 일시",
    )

    def __repr__(self) -> str:
        task_id_str = (
            (self.task_id[:10] + "...") if len(self.task_id) > 10 else self.task_id
        )
        img_name_str = (
            (self.img_name[:10] + "...") if len(self.img_name) > 10 else self.img_name
        )

        return (
            f"<Image(id={self.id}, task_id='{task_id_str}', img_name='{img_name_str}')>"
        )
