from decimal import Decimal

from pydantic import BaseModel, validator

from intranet.trip.src.api.schemas import Person
from intranet.trip.src.api.schemas.common import LocalizedString
from intranet.trip.src.config import settings
from intranet.trip.src.enums import DocumentType, OverpriceWorkflow, ServiceStatus, ServiceType
from intranet.trip.src.models import ServiceActions


class ServiceId(BaseModel):
    service_id: int


class ServiceCreate(BaseModel):
    trip_id: int
    person_id: int
    search_id: int
    option_number: int
    key: str
    detail_index: int = None
    type: ServiceType
    overprice_workflow: OverpriceWorkflow = None
    seat_number: int = None

    # TODO: BTRIP-1372 добавить валидатор для seat_number
    # @validator('seat_number', always=True)
    # def seat_number_is_required_for_rail(cls, v, values):
    #     if values.get('type') == ServiceType.rail and v is None:
    #         raise ValueError('field required')
    #     return v


class Service(BaseModel):
    service_id: int
    trip_id: int
    person_id: int
    person: Person = None
    type: ServiceType
    status: ServiceStatus
    ordering: int = 0
    boarding_pass: str = None
    is_broken: bool = None
    is_authorized: bool
    document_id: int = None

    provider_service_id: int
    provider_order_id: int = None
    provider_document_id: int = None
    provider_url: str = None

    seat_number: int = None
    actions: ServiceActions
    in_process_of_cancelling: bool = False

    @validator('provider_url', always=True)
    def generate_provider_url(cls, v, values):
        order_id = values.get('provider_order_id')
        service_id = values.get('provider_service_id')
        if order_id and service_id:
            return f'{settings.trip_base_url}/api/aeroclub/orders/{order_id}/services/{service_id}'
        return v


class ServiceDocumentIn(BaseModel):
    provider_profile_id: int = None
    provider_document_id: int = None


class ServiceReserveIn(BaseModel):
    seat_number: int


class ServiceUpdateIn(BaseModel):
    seat_number: int


class Country(BaseModel):
    id: int
    code: str = None
    name: LocalizedString = None


class City(BaseModel):
    id: int
    code: str = None
    name: LocalizedString = None
    country: Country


class GeoPosition(BaseModel):
    latitude: Decimal
    longitude: Decimal


class Address(BaseModel):
    name: LocalizedString = None
    coordinates: GeoPosition = None


class ServiceAnalytics(BaseModel):
    is_corporate_tariff: bool
    is_travel_policy_compliant: bool
    travel_policy_violation_reason: bool = None
    travel_policy_violations: list[str]


class TravellerDocument(BaseModel):
    id: int
    type: DocumentType
    document_number: str
    first_name: str = None
    last_name: str = None
    middle_name: str = None


class TravellerTicket(BaseModel):
    location: str


class DocumentAttachment(BaseModel):
    url: str = None
    name: str = None
    content_type: str = None
    length: int = None


class ServiceDocument(BaseModel):
    attachments: list[DocumentAttachment]


class ServiceBase(BaseModel):
    # то, что отдаем уже сейчас
    service_id: int
    trip_id: int
    person_id: int
    person: Person = None
    type: ServiceType
    status: ServiceStatus
    is_broken: bool
    is_authorized: bool
    in_process_of_cancelling: bool = False

    provider_service_id: int  # deprecated
    provider_order_id: int  # deprecated
    provider_document_id: int = None  # deprecated
    seat_number: int = None  # deprecated
    actions: ServiceActions

    analytics: ServiceAnalytics
    tariff_total: Decimal
    documents: list[ServiceDocument]


class Airport(BaseModel):
    id: int
    code: str = None
    name: LocalizedString = None
    address: Address = None
    image_url: str = None
    terminal: str = None
    time_zone_offset: str = None
    # city: City


class Baggage(BaseModel):
    quantity: int
    weigh_measurement: int = None


class Airline(BaseModel):
    code: str = None
    code_ru: str = None
    name: LocalizedString = None


class AviaSegment(BaseModel):
    flight_number: str
    airline: Airline
    aircraft: LocalizedString = None
    baggage: Baggage
    # class_of_service: ServiceClass
    # departure_from: AirportLocation
    # arrival_to: AirportLocation
    departure_at: str
    arrival_at: str
    duration: str
    fare_bases: str = None
    fare_family: str = None


class AviaLeg(BaseModel):
    departure_from: Airport
    arrival_to: Airport
    departure_at: str  # dt
    departure_at_utc: str  # dt, зачем нам две даты, лучше одну с таймзоной?
    arrival_at: str
    arrival_at_utc: str
    # cabin_class: CabinClass  # NotSet, Economy, Comfort, Business, First
    transfers: int
    duration: str
    segments: list[AviaSegment]


class AviaService(ServiceBase):
    legs: list[AviaLeg]


class HotelService(ServiceBase):
    address: Address = None
    name: LocalizedString = None
    stars: int
    # location: ACAirportLocation = None
    start_at: str
    start_at_utc: str
    end_at: str
    end_at_utc: str


# class CodeName(BaseModel):
#     code: str = None
#     name: Name = None


class RailCarriage(BaseModel):
    # class_of_service: CodeName
    electronic_registration_allowed: bool
    number: str
    type: LocalizedString


class RailInfo(BaseModel):
    category_name: str = None
    name: LocalizedString = None
    number: str = None


class RailService(ServiceBase):
    departure_at: str  # dt timezone?
    # departure_from: ACTrainStationLocation  # ?
    arrival_at: str  # dt timezone?
    # arrival_to: ACTrainStationLocation
    duration: str  # это в чем и нельзя ли посчитать через две даты
    carriage: RailCarriage  # ??
    rail_info: RailInfo  # train  ??
