from typing import List, Optional

from sqlalchemy.orm import Session

from app.core.entities.delivery_order import DeliveryOrderEntity
from app.infrastructure.database.models.delivery_orders import DeliveryOrder
from app.infrastructure.database.repository.delivery_order_repository import DeliveryOrdersRepository


class DeliveryOrdersService:
    def __init__(self, db: Session):
        self.repository = DeliveryOrdersRepository(db)

    def get_all_delivery_orders(self) -> List[DeliveryOrderEntity]:
        delivery_orders = self.repository.get_all_with_trucks()
        return [
            DeliveryOrderEntity(
                id=o.id,
                order_datetime=o.order_datetime,
                count_trucks=o.count_trucks,
                deadline=o.deadline,
                price=round(o.price, 2),
                truck_id=o.truck_id,
                truck_name=o.truck.name,
                truck_capacity=o.truck.capacity,
                total_order_id=o.total_order_id,
                estimated_route_time_in_minutes=o.estimated_route_time_in_minutes,
            )
            for o in delivery_orders
        ]

    def get_delivery_order_by_total_order_id(self, total_order_id):
        delivery_orders = self.repository.get_all_by_total_order_id(total_order_id)
        return [
            DeliveryOrderEntity(
                id=o.id,
                order_datetime=o.order_datetime,
                count_trucks=o.count_trucks,
                deadline=o.deadline,
                price=o.price,
                truck_id=o.truck_id,
                truck_name=o.truck.name,
                truck_capacity=o.truck.capacity,
                total_order_id=o.total_order_id,
                estimated_route_time_in_minutes=o.estimated_route_time_in_minutes,
                route=o.route,
            )
            for o in delivery_orders
        ]

    def get_delivery_order_by_id(self, delivery_order_id: int) -> Optional[DeliveryOrderEntity]:
        delivery_order = self.repository.get_by_id(delivery_order_id)
        if delivery_order:
            return DeliveryOrderEntity(
                id=delivery_order.id,
                order_datetime=delivery_order.order_datetime,
                count_trucks=delivery_order.count_trucks,
                deadline=delivery_order.deadline,
                price=delivery_order.price,
                truck_id=delivery_order.truck_id,
                truck_name=delivery_order.truck.name,
                truck_capacity=delivery_order.truck.capacity,
                total_order_id=delivery_order.total_order_id,
                estimated_route_time_in_minutes=delivery_order.estimated_route_time_in_minutes,
                route=delivery_order.route,
            )
        return None

    def create_delivery_order(self, entity: DeliveryOrderEntity) -> DeliveryOrderEntity:
        delivery_order_model = DeliveryOrder(
            order_datetime=entity.order_datetime,
            count_trucks=entity.count_trucks,
            deadline=entity.deadline,
            price=entity.price,
            truck_id=entity.truck_id,
            total_order_id=entity.total_order_id,
            estimated_route_time_in_minutes=entity.estimated_route_time_in_minutes,
            route=entity.route,
        )
        created_delivery_order = self.repository.create(delivery_order_model)
        return DeliveryOrderEntity(
            id=created_delivery_order.id,
            order_datetime=created_delivery_order.order_datetime,
            count_trucks=created_delivery_order.count_trucks,
            deadline=created_delivery_order.deadline,
            price=created_delivery_order.price,
            truck_id=created_delivery_order.truck_id,
            total_order_id=created_delivery_order.total_order_id,
            estimated_route_time_in_minutes=created_delivery_order.estimated_route_time_in_minutes,
            route=created_delivery_order.route,
        )

    def update_delivery_order(self, delivery_order_id: int, entity: DeliveryOrderEntity) -> Optional[
        DeliveryOrderEntity
    ]:
        delivery_order_model = self.repository.get_by_id(delivery_order_id)
        if delivery_order_model:
            delivery_order_model.order_datetime = entity.order_datetime
            delivery_order_model.count_trucks = entity.count_trucks
            delivery_order_model.deadline = entity.deadline
            delivery_order_model.price = entity.price
            delivery_order_model.truck_id = entity.truck_id
            delivery_order_model.total_order_id = entity.total_order_id
            delivery_order_model.estimated_route_time_in_minutes = entity.estimated_route_time_in_minutes
            delivery_order_model.route = entity.route
            self.repository.update(delivery_order_model)
            return DeliveryOrderEntity(
                id=delivery_order_model.id,
                order_datetime=delivery_order_model.order_datetime,
                count_trucks=delivery_order_model.count_trucks,
                deadline=delivery_order_model.deadline,
                price=delivery_order_model.price,
                truck_id=delivery_order_model.truck_id,
                total_order_id=delivery_order_model.total_order_id,
                estimated_route_time_in_minutes=delivery_order_model.estimated_route_time_in_minutes,
                route=delivery_order_model.route,
            )
        return None

    def update_delivery_order_route(
            self,
            delivery_order_id: int,
            estimated_route_time_in_minutes: float,
            route: List[List[float]]
    ) -> Optional[DeliveryOrderEntity]:

        delivery_order_model = self.repository.get_by_id(delivery_order_id)

        if delivery_order_model:
            if estimated_route_time_in_minutes is not None:
                delivery_order_model.estimated_route_time_in_minutes = round(estimated_route_time_in_minutes)
            if route is not None:
                delivery_order_model.route = route

            self.repository.update(delivery_order_model)

            return DeliveryOrderEntity(
                id=delivery_order_model.id,
                order_datetime=delivery_order_model.order_datetime,
                count_trucks=delivery_order_model.count_trucks,
                deadline=delivery_order_model.deadline,
                price=delivery_order_model.price,
                truck_id=delivery_order_model.truck_id,
                total_order_id=delivery_order_model.total_order_id,
                estimated_route_time_in_minutes=delivery_order_model.estimated_route_time_in_minutes,
                route=delivery_order_model.route,
            )

        return None

    def delete_delivery_order(self, delivery_order_id: int) -> bool:
        return self.repository.delete(delivery_order_id) is not None
