import uuid
from datetime import date, datetime
from decimal import Decimal

from pydantic import BaseModel, Field, model_validator

from app.models.absence import AbsenceStatus
from app.models.absence_type import AbsenceCategory


# ── AbsenceType ───────────────────────────────────────────────────────────────

class AbsenceTypeOut(BaseModel):
    model_config = {"from_attributes": True}

    id: uuid.UUID
    company_id: uuid.UUID
    name: str
    color: str
    category: AbsenceCategory
    requires_approval: bool
    deducts_vacation: bool
    affects_overtime_balance: bool
    requires_certificate: bool
    certificate_after_days: int
    is_paid: bool
    max_days_per_year: int | None
    is_active: bool


class AbsenceTypeCreate(BaseModel):
    name: str = Field(min_length=1, max_length=255)
    color: str = Field("#3B82F6", pattern=r"^#[0-9A-Fa-f]{6}$")
    category: AbsenceCategory = AbsenceCategory.OTHER
    requires_approval: bool = True
    deducts_vacation: bool = False
    affects_overtime_balance: bool = False
    requires_certificate: bool = False
    certificate_after_days: int = Field(3, ge=0, le=365)
    is_paid: bool = True
    max_days_per_year: int | None = Field(None, ge=1)


class AbsenceTypeUpdate(BaseModel):
    name: str | None = Field(None, min_length=1, max_length=255)
    color: str | None = Field(None, pattern=r"^#[0-9A-Fa-f]{6}$")
    category: AbsenceCategory | None = None
    requires_approval: bool | None = None
    deducts_vacation: bool | None = None
    affects_overtime_balance: bool | None = None
    requires_certificate: bool | None = None
    certificate_after_days: int | None = Field(None, ge=0, le=365)
    is_paid: bool | None = None
    max_days_per_year: int | None = Field(None, ge=1)
    is_active: bool | None = None


# ── Absence ───────────────────────────────────────────────────────────────────

class AbsenceOut(BaseModel):
    model_config = {"from_attributes": True}

    id: uuid.UUID
    user_id: uuid.UUID
    type_id: uuid.UUID
    start_date: date
    end_date: date
    half_day_start: bool
    half_day_end: bool
    working_days: float
    fza_hours: Decimal | None = None
    status: AbsenceStatus
    approved_by: uuid.UUID | None
    first_approved_by: uuid.UUID | None = None
    substitute_id: uuid.UUID | None
    note: str | None
    correction_note: str | None
    rejection_reason: str | None
    certificate_required_by: date | None = None
    certificate_received_at: date | None = None
    created_at: datetime


class AbsenceCreate(BaseModel):
    type_id: uuid.UUID
    start_date: date
    end_date: date
    half_day_start: bool = False
    half_day_end: bool = False
    substitute_id: uuid.UUID | None = None
    note: str | None = None
    for_user_id: uuid.UUID | None = None  # HR/Admin: Abwesenheit für anderen Mitarbeiter anlegen
    fza_hours: Decimal | None = Field(
        None,
        ge=Decimal("0.25"),
        le=Decimal("24"),
        description="FZA in Stunden (statt Tagen); nur bei eintägigem Zeitraum erlaubt.",
    )

    def model_post_init(self, __context) -> None:
        if self.end_date < self.start_date:
            raise ValueError("end_date must be >= start_date")
        if self.fza_hours is not None and self.start_date != self.end_date:
            raise ValueError("fza_hours ist nur erlaubt wenn start_date == end_date (eintägiger FZA).")


class AbsenceUpdate(BaseModel):
    type_id: uuid.UUID | None = None
    start_date: date | None = None
    end_date: date | None = None
    half_day_start: bool | None = None
    half_day_end: bool | None = None
    substitute_id: uuid.UUID | None = None
    note: str | None = None
    correction_note: str | None = None  # Pflicht bei Änderung genehmigter Anträge (Mitarbeiter)

    def model_post_init(self, __context) -> None:
        if self.start_date and self.end_date and self.end_date < self.start_date:
            raise ValueError("end_date must be >= start_date")


class AbsenceReject(BaseModel):
    rejection_reason: str = Field(min_length=1)


class CancellationRequest(BaseModel):
    reason: str | None = Field(None, max_length=1000)


# ── Kommentare ────────────────────────────────────────────────────────────────

class AbsenceCommentOut(BaseModel):
    model_config = {"from_attributes": True}

    id: uuid.UUID
    absence_id: uuid.UUID
    author_id: uuid.UUID | None
    author_name: str | None = None
    body: str
    is_system: bool
    created_at: datetime


class AbsenceCommentCreate(BaseModel):
    body: str = Field(min_length=1, max_length=2000)


class AbsenceListResponse(BaseModel):
    total: int
    items: list[AbsenceOut]


# ── Krankmeldung ──────────────────────────────────────────────────────────────

class QuickSickIn(BaseModel):
    start_date: date
    end_date: date

    def model_post_init(self, __context) -> None:
        if self.end_date < self.start_date:
            raise ValueError("end_date must be >= start_date")


class CertificateMarkIn(BaseModel):
    received_at: date | None = None  # default = heute


class SickStatsOut(BaseModel):
    user_id: uuid.UUID
    user_name: str
    personnel_number: str | None = None
    episodes: int
    total_days: float
    bradford_factor: float
    certificates_overdue: int


# ── VacationBalance ───────────────────────────────────────────────────────────

class VacationBalanceOut(BaseModel):
    model_config = {"from_attributes": True}

    id: uuid.UUID
    user_id: uuid.UUID
    year: int
    entitled_days: int
    special_days: int = 0
    carried_over: int
    used_days: int
    total_days: int
    remaining_days: int
    # Effektiv verfügbar: berücksichtigt verfallenen Resturlaub (zur Laufzeit befüllt).
    available_days: int = 0
    pending_days: float = 0
    # Resturlaub-Verfall (wird zur Laufzeit befüllt, nicht in DB)
    carried_over_expires_at: date | None = None
    carried_over_expired: bool = False


class VacationBalanceUpdate(BaseModel):
    entitled_days: int | None = Field(None, ge=0, le=365)
    special_days: int | None = Field(None, ge=0, le=365)
    carried_over: int | None = Field(None, ge=0, le=365)


# ── PublicHoliday ─────────────────────────────────────────────────────────────

class PublicHolidayOut(BaseModel):
    model_config = {"from_attributes": True}

    id: uuid.UUID
    country: str
    state: str | None
    date: date
    name: str
    year: int


class PublicHolidayCreate(BaseModel):
    country: str = Field("DE", min_length=2, max_length=10)
    state: str | None = Field(None, max_length=10)
    date: date
    name: str = Field(min_length=1, max_length=255)


# ── OvertimeBalance ───────────────────────────────────────────────────────────

class OvertimeBalanceOut(BaseModel):
    total_hours: float
    taken_hours: float
    available_hours: float


# ── Calendar ──────────────────────────────────────────────────────────────────

class CalendarEntry(BaseModel):
    user_id: uuid.UUID
    user_name: str
    absence_id: uuid.UUID
    type_name: str
    type_color: str
    start_date: date
    end_date: date
    status: AbsenceStatus
    working_days: float
