"""
Pydantic schemas for admin/staff booking creation.
"""
from pydantic import BaseModel, Field, field_validator, model_validator
from typing import Optional, List
from datetime import datetime
from .booking import ServiceItemSchema, InvoiceInfoSchema


class AdminCreateBookingRequest(BaseModel):
    """Schema for admin/staff creating a booking on behalf of a user."""
    user_id: int = Field(..., gt=0, description="User ID for whom the booking is created")
    room_id: int = Field(..., gt=0, description="Room ID")
    check_in_date: str = Field(..., description="Check-in date (YYYY-MM-DD or ISO format)")
    check_out_date: str = Field(..., description="Check-out date (YYYY-MM-DD or ISO format)")
    total_price: float = Field(..., gt=0, description="Total booking price")
    guest_count: int = Field(1, gt=0, le=20, description="Number of guests")
    notes: Optional[str] = Field(None, max_length=1000, description="Special requests/notes")
    payment_method: str = Field("cash", description="Payment method (cash, stripe, paypal)")
    payment_status: str = Field("unpaid", description="Payment status (unpaid, full, deposit)")
    promotion_code: Optional[str] = Field(None, max_length=50)
    status: str = Field("confirmed", description="Booking status (pending, confirmed, etc.)")
    services: Optional[List[ServiceItemSchema]] = Field(default_factory=list)
    invoice_info: Optional[InvoiceInfoSchema] = None

    @field_validator('check_in_date', 'check_out_date')
    @classmethod
    def validate_date_format(cls, v: str) -> str:
        """Validate date format."""
        try:
            if 'T' in v or 'Z' in v or '+' in v:
                datetime.fromisoformat(v.replace('Z', '+00:00'))
            else:
                datetime.strptime(v, '%Y-%m-%d')
            return v
        except (ValueError, TypeError):
            raise ValueError('Invalid date format. Use YYYY-MM-DD or ISO format.')

    @field_validator('payment_method')
    @classmethod
    def validate_payment_method(cls, v: str) -> str:
        """Validate payment method."""
        allowed_methods = ['cash', 'stripe', 'paypal', 'borica']
        if v not in allowed_methods:
            raise ValueError(f'Payment method must be one of: {", ".join(allowed_methods)}')
        return v

    @field_validator('payment_status')
    @classmethod
    def validate_payment_status(cls, v: str) -> str:
        """Validate payment status."""
        allowed_statuses = ['unpaid', 'full', 'deposit']
        if v not in allowed_statuses:
            raise ValueError(f'Payment status must be one of: {", ".join(allowed_statuses)}')
        return v

    @field_validator('status')
    @classmethod
    def validate_status(cls, v: str) -> str:
        """Validate booking status."""
        allowed_statuses = ['pending', 'confirmed', 'checked_in', 'checked_out', 'cancelled']
        if v not in allowed_statuses:
            raise ValueError(f'Status must be one of: {", ".join(allowed_statuses)}')
        return v

    @model_validator(mode='after')
    def validate_dates(self):
        """Validate that check-out is after check-in."""
        check_in = self.check_in_date
        check_out = self.check_out_date
        
        if check_in and check_out:
            try:
                if 'T' in check_in or 'Z' in check_in or '+' in check_in:
                    check_in_dt = datetime.fromisoformat(check_in.replace('Z', '+00:00'))
                else:
                    check_in_dt = datetime.strptime(check_in, '%Y-%m-%d')
                
                if 'T' in check_out or 'Z' in check_out or '+' in check_out:
                    check_out_dt = datetime.fromisoformat(check_out.replace('Z', '+00:00'))
                else:
                    check_out_dt = datetime.strptime(check_out, '%Y-%m-%d')
                
                if check_in_dt >= check_out_dt:
                    raise ValueError('Check-out date must be after check-in date')
            except (ValueError, TypeError) as e:
                if 'Check-out date' in str(e):
                    raise
                raise ValueError('Invalid date format')
        
        return self

