"""
Pydantic data models for Location (Lokaliteter) Module.

Provides request/response validation for all location-related endpoints.
Includes models for locations, contacts, operating hours, services, capacity, and audit logs.
"""

from pydantic import BaseModel, Field, field_validator
from typing import Optional, List
from datetime import datetime, time
from decimal import Decimal


# ============================================================================
# 1. LOCATION MODELS
# ============================================================================

class LocationBase(BaseModel):
    """Shared fields for location models"""
    name: str = Field(..., min_length=1, max_length=255, description="Location name (unique)")
    location_type: str = Field(
        ...,
        description="Type: kompleks | bygning | etage | customer_site | rum | kantine | moedelokale | vehicle"
    )
    parent_location_id: Optional[int] = Field(
        None,
        description="Parent location ID for hierarchy (e.g., building -> floor -> room)"
    )
    customer_id: Optional[int] = Field(
        None,
        description="Related customer ID (optional, can be used for any location type)"
    )
    address_street: Optional[str] = Field(None, max_length=255)
    address_city: Optional[str] = Field(None, max_length=100)
    address_postal_code: Optional[str] = Field(None, max_length=20)
    address_country: str = Field("DK", max_length=100)
    latitude: Optional[float] = Field(None, ge=-90, le=90)
    longitude: Optional[float] = Field(None, ge=-180, le=180)
    phone: Optional[str] = Field(None, max_length=20)
    email: Optional[str] = None
    notes: Optional[str] = None
    is_active: bool = Field(True, description="Whether location is active")

    @field_validator('location_type')
    @classmethod
    def validate_location_type(cls, v):
        """Validate location_type is one of allowed values"""
        allowed = ['kompleks', 'bygning', 'etage', 'customer_site', 'rum', 'kantine', 'moedelokale', 'vehicle']
        if v not in allowed:
            raise ValueError(f'location_type must be one of {allowed}')
        return v


class LocationCreate(LocationBase):
    """Request model for creating a new location"""
    pass


class LocationUpdate(BaseModel):
    """Request model for updating location (all fields optional)"""
    name: Optional[str] = Field(None, min_length=1, max_length=255)
    location_type: Optional[str] = Field(
        None,
        description="Type: kompleks | bygning | etage | customer_site | rum | kantine | moedelokale | vehicle"
    )
    parent_location_id: Optional[int] = None
    customer_id: Optional[int] = None
    address_street: Optional[str] = Field(None, max_length=255)
    address_city: Optional[str] = Field(None, max_length=100)
    address_postal_code: Optional[str] = Field(None, max_length=20)
    address_country: Optional[str] = Field(None, max_length=100)
    latitude: Optional[float] = Field(None, ge=-90, le=90)
    longitude: Optional[float] = Field(None, ge=-180, le=180)
    phone: Optional[str] = Field(None, max_length=20)
    email: Optional[str] = None
    notes: Optional[str] = None
    is_active: Optional[bool] = None

    @field_validator('location_type')
    @classmethod
    def validate_location_type(cls, v):
        if v is None:
            return v
        allowed = ['kompleks', 'bygning', 'etage', 'customer_site', 'rum', 'kantine', 'moedelokale', 'vehicle']
        if v not in allowed:
            raise ValueError(f'location_type must be one of {allowed}')
        return v


class Location(LocationBase):
    """Full location response model with database fields"""
    id: int
    parent_location_name: Optional[str] = None
    customer_name: Optional[str] = None
    created_at: datetime
    updated_at: datetime
    deleted_at: Optional[datetime] = None
    created_by_user_id: Optional[int] = None

    class Config:
        from_attributes = True


# ============================================================================
# 2. CONTACT MODELS
# ============================================================================

class ContactBase(BaseModel):
    """Shared fields for contact models"""
    contact_name: str = Field(..., min_length=1, max_length=255)
    contact_email: Optional[str] = None
    contact_phone: Optional[str] = Field(None, max_length=20)
    role: Optional[str] = Field(
        None,
        max_length=100,
        description="e.g., Manager, Technician, Administrator"
    )


class ContactCreate(BaseModel):
    """Request model for linking an existing global contact to a location"""
    existing_contact_id: int = Field(
        ...,
        ge=1,
        description="ID of existing global contact"
    )
    role: Optional[str] = Field(
        None,
        max_length=100,
        description="Optional location-specific role override"
    )
    is_primary: bool = Field(False, description="Set as primary contact for location")


class ContactUpdate(BaseModel):
    """Request model for updating contact (all fields optional)"""
    contact_name: Optional[str] = Field(None, min_length=1, max_length=255)
    contact_email: Optional[str] = None
    contact_phone: Optional[str] = Field(None, max_length=20)
    role: Optional[str] = Field(None, max_length=100)
    is_primary: Optional[bool] = None


class Contact(ContactBase):
    """Full contact response model"""
    id: int
    location_id: int
    related_contact_id: Optional[int] = None
    is_primary: bool
    created_at: datetime

    class Config:
        from_attributes = True


# ============================================================================
# 3. OPERATING HOURS MODELS
# ============================================================================

class OperatingHoursBase(BaseModel):
    """Shared fields for operating hours models"""
    day_of_week: int = Field(
        ...,
        ge=0,
        le=6,
        description="0=Monday...6=Sunday"
    )
    open_time: Optional[time] = Field(None, description="HH:MM format")
    close_time: Optional[time] = Field(None, description="HH:MM format")
    is_open: bool = Field(True, description="Is location open on this day?")
    notes: Optional[str] = Field(None, max_length=255)


class OperatingHoursCreate(OperatingHoursBase):
    """Request model for creating operating hours"""
    pass


class OperatingHoursUpdate(BaseModel):
    """Request model for updating operating hours (all fields optional)"""
    open_time: Optional[time] = None
    close_time: Optional[time] = None
    is_open: Optional[bool] = None
    notes: Optional[str] = None


class OperatingHours(OperatingHoursBase):
    """Full operating hours response model"""
    id: int
    location_id: int

    class Config:
        from_attributes = True

    @property
    def day_name(self) -> str:
        """Get day name from day_of_week (0=Monday, 6=Sunday)"""
        days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
        return days[self.day_of_week]


# ============================================================================
# 4. SERVICE MODELS
# ============================================================================

class ServiceBase(BaseModel):
    """Shared fields for service models"""
    service_name: str = Field(..., min_length=1, max_length=255)
    is_available: bool = Field(True)


class ServiceCreate(ServiceBase):
    """Request model for creating service"""
    pass


class ServiceUpdate(BaseModel):
    """Request model for updating service (all fields optional)"""
    service_name: Optional[str] = Field(None, min_length=1, max_length=255)
    is_available: Optional[bool] = None


class Service(ServiceBase):
    """Full service response model"""
    id: int
    location_id: int
    created_at: datetime

    class Config:
        from_attributes = True


# ============================================================================
# 5. CAPACITY MODELS
# ============================================================================

class CapacityBase(BaseModel):
    """Shared fields for capacity models"""
    capacity_type: str = Field(
        ...,
        max_length=100,
        description="e.g., rack_units, square_meters, storage_boxes"
    )
    total_capacity: Decimal = Field(..., decimal_places=2, gt=0)
    used_capacity: Decimal = Field(0, decimal_places=2, ge=0)

    @field_validator('used_capacity')
    @classmethod
    def validate_used_capacity(cls, v, info):
        """Ensure used_capacity doesn't exceed total_capacity"""
        if 'total_capacity' in info.data:
            if v > info.data['total_capacity']:
                raise ValueError('used_capacity cannot exceed total_capacity')
        return v


class CapacityCreate(CapacityBase):
    """Request model for creating capacity"""
    pass


class CapacityUpdate(BaseModel):
    """Request model for updating capacity (all fields optional)"""
    total_capacity: Optional[Decimal] = Field(None, decimal_places=2, gt=0)
    used_capacity: Optional[Decimal] = Field(None, decimal_places=2, ge=0)


class Capacity(CapacityBase):
    """Full capacity response model"""
    id: int
    location_id: int
    last_updated: datetime

    class Config:
        from_attributes = True

    @property
    def usage_percentage(self) -> float:
        """Calculate usage percentage (0-100)"""
        if self.total_capacity == 0:
            return 0.0
        return float((self.used_capacity / self.total_capacity) * 100)

    @property
    def available_capacity(self) -> Decimal:
        """Calculate remaining capacity"""
        return self.total_capacity - self.used_capacity


# ============================================================================
# 6. BULK OPERATION MODELS
# ============================================================================

class BulkUpdateRequest(BaseModel):
    """Request for bulk updating multiple locations"""
    ids: List[int] = Field(..., min_items=1, description="Location IDs to update")
    updates: dict = Field(..., description="Fields to update (name, is_active, etc.)")


class BulkDeleteRequest(BaseModel):
    """Request for bulk deleting multiple locations"""
    ids: List[int] = Field(..., min_items=1, description="Location IDs to soft-delete")


class LocationWizardRoom(BaseModel):
    """Room definition for location wizard"""
    name: str = Field(..., min_length=1, max_length=255)
    location_type: str = Field("rum", description="Type: rum | kantine | moedelokale")
    is_active: bool = Field(True, description="Whether room is active")

    @field_validator('location_type')
    @classmethod
    def validate_room_type(cls, v):
        allowed = ['rum', 'kantine', 'moedelokale']
        if v not in allowed:
            raise ValueError(f'location_type must be one of {allowed}')
        return v


class LocationWizardFloor(BaseModel):
    """Floor definition for location wizard"""
    name: str = Field(..., min_length=1, max_length=255)
    location_type: str = Field("etage", description="Type: etage")
    rooms: List[LocationWizardRoom] = Field(default_factory=list)
    is_active: bool = Field(True, description="Whether floor is active")

    @field_validator('location_type')
    @classmethod
    def validate_floor_type(cls, v):
        if v != 'etage':
            raise ValueError('location_type must be etage for floors')
        return v


class LocationWizardCreateRequest(BaseModel):
    """Request for creating a location with floors and rooms"""
    root: LocationCreate
    floors: List[LocationWizardFloor] = Field(..., min_items=1)
    auto_suffix: bool = Field(True, description="Auto-suffix names if duplicates exist")


class LocationWizardCreateResponse(BaseModel):
    """Response for location wizard creation"""
    root_id: int
    floor_ids: List[int] = Field(default_factory=list)
    room_ids: List[int] = Field(default_factory=list)
    created_total: int


# ============================================================================
# 7. RESPONSE MODELS
# ============================================================================

class LocationDetail(Location):
    """Full location response including all related data"""
    hierarchy: List[dict] = Field(default_factory=list, description="Ancestors from root to parent")
    children: List[dict] = Field(default_factory=list, description="Direct child locations")
    hardware: List[dict] = Field(default_factory=list, description="Hardware assigned to this location")
    contacts: List[Contact] = Field(default_factory=list)
    hours: List[OperatingHours] = Field(default_factory=list)
    services: List[Service] = Field(default_factory=list)
    capacity: List[Capacity] = Field(default_factory=list)


class AuditLogEntry(BaseModel):
    """Audit log entry for location changes"""
    id: int
    location_id: int
    event_type: str
    user_id: Optional[int] = None
    changes: dict = Field(
        default_factory=dict,
        description="JSON object with before/after values"
    )
    created_at: datetime

    class Config:
        from_attributes = True


class LocationStats(BaseModel):
    """Statistics about locations"""
    total_locations: int
    active_locations: int
    by_type: dict = Field(default_factory=dict, description="Count by location_type")
    total_contacts: int
    total_services: int
    average_capacity_utilization: float = Field(0.0, ge=0, le=100)


# ============================================================================
# 8. SEARCH & FILTER MODELS
# ============================================================================

class LocationSearchResponse(BaseModel):
    """Response model for location search results"""
    results: List[Location]
    total: int
    query: str


class LocationFilterParams(BaseModel):
    """Query parameters for filtering locations"""
    location_type: Optional[str] = None
    is_active: Optional[bool] = None
    skip: int = Field(0, ge=0)
    limit: int = Field(50, ge=1, le=1000)
