"""
Infrastructure change model for tracking infrastructure modifications.

Tracks changes to infrastructure including DNS, firewall, routing, SSL,
containers, and other infrastructure components with audit trail and
rollback procedures.
"""

from datetime import datetime
from typing import TYPE_CHECKING, Optional

from sqlalchemy import 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 InfrastructureChange(Base, UUIDMixin):
    """
    Infrastructure change model for audit trail of infrastructure modifications.

    Records changes to infrastructure components including DNS configuration,
    firewall rules, routing tables, SSL certificates, containers, service
    configurations, hardware, network, and storage. Tracks before/after state,
    rollback procedures, and verification status for operational safety.

    Attributes:
        work_item_id: Foreign key to work_items table (required)
        session_id: Foreign key to sessions table (required)
        infrastructure_id: Foreign key to infrastructure table
        change_type: Type of infrastructure change
        target_system: System or component that was modified
        before_state: State before the change (configuration snapshot)
        after_state: State after the change (configuration snapshot)
        is_permanent: Whether this is a permanent change or temporary
        rollback_procedure: Instructions for rolling back this change
        verification_performed: Whether verification was performed after change
        verification_notes: Notes about verification testing
        created_at: When the change was made
        work_item: Relationship to WorkItem model
        session: Relationship to Session model
        infrastructure: Relationship to Infrastructure model
    """

    __tablename__ = "infrastructure_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)"
    )

    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: dns, firewall, routing, ssl, container, service_config, hardware, network, storage"
    )

    target_system: Mapped[str] = mapped_column(
        String(255),
        nullable=False,
        doc="System or component that was modified (e.g., 'jupiter', 'UDM-Pro', 'web-container')"
    )

    # State tracking
    before_state: Mapped[Optional[str]] = mapped_column(
        Text,
        doc="Configuration or state before the change (snapshot, config dump, etc.)"
    )

    after_state: Mapped[Optional[str]] = mapped_column(
        Text,
        doc="Configuration or state after the change (snapshot, config dump, etc.)"
    )

    # Change characteristics
    is_permanent: Mapped[bool] = mapped_column(
        Boolean,
        default=True,
        server_default="1",
        nullable=False,
        doc="Whether this is a permanent change or temporary (e.g., for testing)"
    )

    rollback_procedure: Mapped[Optional[str]] = mapped_column(
        Text,
        doc="Instructions for rolling back this change if needed"
    )

    # Verification
    verification_performed: Mapped[bool] = mapped_column(
        Boolean,
        default=False,
        server_default="0",
        nullable=False,
        doc="Whether verification testing was performed after the change"
    )

    verification_notes: Mapped[Optional[str]] = mapped_column(
        Text,
        doc="Notes about verification testing (what was tested, results, etc.)"
    )

    # 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="infrastructure_changes",
        doc="Relationship to WorkItem model"
    )

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

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

    # Constraints and indexes
    __table_args__ = (
        CheckConstraint(
            "change_type IN ('dns', 'firewall', 'routing', 'ssl', 'container', 'service_config', 'hardware', 'network', 'storage')",
            name="ck_infrastructure_changes_type"
        ),
        Index("idx_infra_changes_work_item", "work_item_id"),
        Index("idx_infra_changes_session", "session_id"),
        Index("idx_infra_changes_infrastructure", "infrastructure_id"),
    )

    def __repr__(self) -> str:
        """String representation of the infrastructure change."""
        return f"<InfrastructureChange(type='{self.change_type}', target='{self.target_system}', permanent={self.is_permanent})>"
