"""
Database change model for tracking database schema and data modifications.

Tracks database changes including schema modifications, data updates, index
creation, optimizations, and cleanup operations with backup tracking.
"""

from datetime import datetime
from typing import TYPE_CHECKING, Optional

from sqlalchemy import BigInteger, Boolean, CHAR, CheckConstraint, ForeignKey, Index, String, Text, TIMESTAMP
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql import func

from .base import Base, UUIDMixin

if TYPE_CHECKING:
    from .infrastructure import Infrastructure
    from .session import Session
    from .work_item import WorkItem


class DatabaseChange(Base, UUIDMixin):
    """
    Database change model for tracking database modifications.

    Records all database schema and data changes including DDL operations,
    data modifications, index management, optimizations, and cleanup tasks.
    Tracks affected rows, backup status, and freed space for audit and
    rollback purposes.

    Attributes:
        work_item_id: Foreign key to work_items table (required)
        session_id: Foreign key to sessions table (required)
        database_name: Name of the database that was modified
        infrastructure_id: Foreign key to infrastructure table
        change_type: Type of database change
        sql_executed: SQL statements that were executed
        rows_affected: Number of rows affected by the change
        size_freed_bytes: Bytes freed by cleanup operations
        backup_taken: Whether a backup was taken before the change
        backup_location: Path or identifier of the backup
        created_at: When the change was made
        work_item: Relationship to WorkItem model
        session: Relationship to Session model
        infrastructure: Relationship to Infrastructure model
    """

    __tablename__ = "database_changes"

    # Foreign keys
    work_item_id: Mapped[str] = mapped_column(
        CHAR(36),
        ForeignKey("work_items.id", ondelete="CASCADE"),
        nullable=False,
        doc="Foreign key to work_items table (required)"
    )

    session_id: Mapped[str] = mapped_column(
        CHAR(36),
        ForeignKey("sessions.id", ondelete="CASCADE"),
        nullable=False,
        doc="Foreign key to sessions table (required)"
    )

    database_name: Mapped[str] = mapped_column(
        String(255),
        nullable=False,
        doc="Name of the database that was modified"
    )

    infrastructure_id: Mapped[Optional[str]] = mapped_column(
        CHAR(36),
        ForeignKey("infrastructure.id", ondelete="SET NULL"),
        doc="Foreign key to infrastructure table"
    )

    # Change details
    change_type: Mapped[Optional[str]] = mapped_column(
        String(50),
        doc="Type of change: schema, data, index, optimization, cleanup, migration"
    )

    sql_executed: Mapped[Optional[str]] = mapped_column(
        Text,
        doc="SQL statements that were executed"
    )

    rows_affected: Mapped[Optional[int]] = mapped_column(
        BigInteger,
        doc="Number of rows affected by the change"
    )

    size_freed_bytes: Mapped[Optional[int]] = mapped_column(
        BigInteger,
        doc="Bytes freed by cleanup operations"
    )

    # Backup tracking
    backup_taken: Mapped[bool] = mapped_column(
        Boolean,
        default=False,
        server_default="0",
        nullable=False,
        doc="Whether a backup was taken before the change"
    )

    backup_location: Mapped[Optional[str]] = mapped_column(
        String(500),
        doc="Path or identifier of the backup"
    )

    # Timestamp
    created_at: Mapped[datetime] = mapped_column(
        TIMESTAMP,
        nullable=False,
        server_default=func.now(),
        doc="When the change was made"
    )

    # Relationships
    work_item: Mapped["WorkItem"] = relationship(
        "WorkItem",
        back_populates="database_changes",
        doc="Relationship to WorkItem model"
    )

    session: Mapped["Session"] = relationship(
        "Session",
        back_populates="database_changes",
        doc="Relationship to Session model"
    )

    infrastructure: Mapped[Optional["Infrastructure"]] = relationship(
        "Infrastructure",
        back_populates="database_changes",
        doc="Relationship to Infrastructure model"
    )

    # Constraints and indexes
    __table_args__ = (
        CheckConstraint(
            "change_type IN ('schema', 'data', 'index', 'optimization', 'cleanup', 'migration')",
            name="ck_database_changes_type"
        ),
        Index("idx_db_changes_work_item", "work_item_id"),
        Index("idx_db_changes_database", "database_name"),
    )

    def __repr__(self) -> str:
        """String representation of the database change."""
        return f"<DatabaseChange(database='{self.database_name}', type='{self.change_type}', rows={self.rows_affected})>"
