"""
Billable time model for tracking time entries for billing.

Tracks individual billable time entries with references to work items,
sessions, and clients, including rates, amounts, and billing details.
"""

from datetime import datetime
from typing import TYPE_CHECKING, Optional

from sqlalchemy import Boolean, CHAR, CheckConstraint, ForeignKey, Index, Integer, Numeric, String, Text, TIMESTAMP
from sqlalchemy.orm import Mapped, mapped_column, relationship

from .base import Base, TimestampMixin, UUIDMixin

if TYPE_CHECKING:
    from .client import Client
    from .session import Session
    from .work_item import WorkItem


class BillableTime(Base, UUIDMixin, TimestampMixin):
    """
    Billable time model representing individual billable time entries.

    Tracks time entries for billing purposes with detailed information about
    the work performed, rates applied, and amounts calculated. Links to
    work items, sessions, and clients for comprehensive billing tracking.

    Attributes:
        work_item_id: Foreign key to work_items table
        session_id: Foreign key to sessions table
        client_id: Foreign key to clients table
        start_time: When the billable time started
        end_time: When the billable time ended
        duration_minutes: Duration in minutes (auto-calculated or manual)
        hourly_rate: Hourly rate applied to this time entry
        total_amount: Total billable amount (calculated)
        is_billable: Whether this time entry is actually billable
        description: Description of the work performed
        category: Category of work (consulting, development, support, etc.)
        notes: Additional notes about this time entry
        invoiced_at: When this time entry was invoiced
        invoice_id: Reference to invoice if applicable
    """

    __tablename__ = "billable_time"

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

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

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

    # Time tracking
    start_time: Mapped[datetime] = mapped_column(
        TIMESTAMP,
        nullable=False,
        doc="When the billable time started"
    )

    end_time: Mapped[Optional[datetime]] = mapped_column(
        TIMESTAMP,
        doc="When the billable time ended"
    )

    duration_minutes: Mapped[int] = mapped_column(
        Integer,
        nullable=False,
        doc="Duration in minutes (auto-calculated or manual)"
    )

    # Billing information
    hourly_rate: Mapped[float] = mapped_column(
        Numeric(10, 2),
        nullable=False,
        doc="Hourly rate applied to this time entry"
    )

    total_amount: Mapped[float] = mapped_column(
        Numeric(10, 2),
        nullable=False,
        doc="Total billable amount (calculated: duration * rate)"
    )

    is_billable: Mapped[bool] = mapped_column(
        Boolean,
        default=True,
        server_default="1",
        nullable=False,
        doc="Whether this time entry is actually billable"
    )

    # Work details
    description: Mapped[str] = mapped_column(
        Text,
        nullable=False,
        doc="Description of the work performed"
    )

    category: Mapped[str] = mapped_column(
        String(50),
        nullable=False,
        doc="Category: consulting, development, support, maintenance, troubleshooting, project_work, training, documentation"
    )

    notes: Mapped[Optional[str]] = mapped_column(
        Text,
        doc="Additional notes about this time entry"
    )

    # Invoice tracking
    invoiced_at: Mapped[Optional[datetime]] = mapped_column(
        TIMESTAMP,
        doc="When this time entry was invoiced"
    )

    invoice_id: Mapped[Optional[str]] = mapped_column(
        String(100),
        doc="Reference to invoice if applicable"
    )

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

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

    client: Mapped["Client"] = relationship(
        "Client",
        doc="Relationship to Client model"
    )

    # Constraints and indexes
    __table_args__ = (
        CheckConstraint(
            "category IN ('consulting', 'development', 'support', 'maintenance', 'troubleshooting', 'project_work', 'training', 'documentation')",
            name="ck_billable_time_category"
        ),
        CheckConstraint(
            "duration_minutes > 0",
            name="ck_billable_time_duration_positive"
        ),
        CheckConstraint(
            "hourly_rate >= 0",
            name="ck_billable_time_rate_non_negative"
        ),
        CheckConstraint(
            "total_amount >= 0",
            name="ck_billable_time_amount_non_negative"
        ),
        CheckConstraint(
            "end_time IS NULL OR end_time >= start_time",
            name="ck_billable_time_end_after_start"
        ),
        Index("idx_billable_time_work_item", "work_item_id"),
        Index("idx_billable_time_session", "session_id"),
        Index("idx_billable_time_client", "client_id"),
        Index("idx_billable_time_start", "start_time"),
        Index("idx_billable_time_billable", "is_billable"),
        Index("idx_billable_time_category", "category"),
        Index("idx_billable_time_invoiced", "invoiced_at"),
    )

    def __repr__(self) -> str:
        """String representation of the billable time entry."""
        return f"<BillableTime(client_id='{self.client_id}', duration={self.duration_minutes}min, amount=${self.total_amount})>"
