from fastapi import APIRouter, Response, HTTPException, File, UploadFile
from pydantic import ValidationError
from starlette.status import HTTP_404_NOT_FOUND, HTTP_400_BAD_REQUEST, HTTP_204_NO_CONTENT
from data_objects.routes import Routes
from data_objects.delivery import Delivery, ServiceStatus, ServiceType, DeliveryType
from api.routes import create_route, delete_route
from resources import strings
import pandas as pd

router = APIRouter()
delivery_data: Delivery = Delivery(1, '123', 'John Doe', '555-555-5555', '123 Main St', '', 'FOO BAR',
                                   'EX', 12345, 'USA', 0, 'FOOBAR', DeliveryType.PICK_UP, ServiceType.PICK_UP, ServiceStatus.DELIVERED)


@router.post("", status_code=201, summary="Create a new delivery.", description="This endpoint allows you to create a new delivery entry in the database.", responses={HTTP_400_BAD_REQUEST: {"description": strings.GENERIC_INVALID_DATA_ERROR}})
def create_delivery(new_delivery: Delivery) -> None:
    """
    Args:
        new_delivery (Delivery): The delivery data to be created.
    Example:
    ```
    HTTP POST /deliveries
    {
        "delivery_id": 90045,
        "route_id": "FLNC",
        "receipient_name": "John Doe",
        "receipient_phone": "555-555-5555",
        "address_line_1": "123 Main St",
        "address_line_2": "",
        "receipient_city": "New York",
        "receipient_state": "NY",
        "receipient_zip_code": 12345,
        "receipient_country": "USA",
        "quantity": 2,
        "item_name": "folding table",
        "delivery_type": "DELIVERY",
        "service_type": "WHITE_GLOVES",
        "delivery_status": "DELIVERED",
    }
    ```
    """
    invalid_data_error: HTTPException = HTTPException(
        status_code=HTTP_400_BAD_REQUEST, detail=strings.GENERIC_INVALID_DATA_ERROR)
    try:
        delivery_data.push_to_database(new_delivery)
        create_route(Routes(new_delivery.route_id, new_delivery.delivery_id))
    except ValidationError:
        raise invalid_data_error


@router.post("/upload", status_code=201, summary="Upload an excel sheet of deliveries and routes.", description="This endpoint allows you to upload an excel file of deliveries which will automatically be uploaded to the databse.", responses={HTTP_400_BAD_REQUEST: {"description": strings.GENERIC_INVALID_DATA_ERROR}})
def upload_deliveries(file: UploadFile) -> None:
    """
    Args:
        file: The delivery file to be uploaded.
    Example:
    ```
    HTTP POST /deliveries
    {
        "file": {file data}
    }
    ```
    """
    invalid_data_error: HTTPException = HTTPException(
        status_code=HTTP_400_BAD_REQUEST, detail=strings.GENERIC_INVALID_DATA_ERROR)
    if not file.filename.endswith(".xlsx"):
        raise invalid_data_error

    try:
        file_contents = pd.read_excel(file.file)
        list_of_deliveries: [Delivery] = []
        data_from_db = delivery_data.pull_from_database()
        i: int =  0 if (len(data_from_db) <= 0) else int(data_from_db[-1].delivery_id)
        for _, row in file_contents.iterrows():
            i += 1
            delivery_type: DeliveryType = DeliveryType.DELIVERY
            service_type: ServiceType = ServiceType.THRESHOLD
            match row['Delivery Type']:
                case 'P.frm.Cust':
                    delivery_type = DeliveryType.PICK_UP_FROM_CUST
                case 'P&D - Pickup':
                    delivery_type = DeliveryType.P_AND_D_PICKUP
                case 'P&D - Delivery':
                    delivery_type = DeliveryType.P_AND_D_DELIVERY
                case 'Pickup':
                    delivery_type = DeliveryType.PICK_UP
                case 'Delivery - Even Exchange':
                    delivery_type = DeliveryType.DELIVERY_EVEN_EXC

            match row['Service Type']:
                case 'WHTGLV':
                    service_type = ServiceType.WHITE_GLOVES
                case 'THRSHLD':
                    service_type = ServiceType.THRESHOLD
                case 'ROC':
                    service_type = ServiceType.ROOM_OF_CHOICE
                case 'PICKUP':
                    service_type = ServiceType.PICK_UP

            list_of_deliveries.append(Delivery(
                delivery_id=i,
                route_id=row['Route'],
                recipient_name=row['Recipient_Name'],
                recipient_phone=row['Recipient_Phone'],
                address_line_1=row['Address_Line1'],
                address_line_2=row['Address_Line2'],
                recipient_city=row['City/Town'],
                recipient_state=row['State/Province'],
                recipient_zip_code=row['Postal_Code'],
                recipient_country=row['Country'],
                quantity=row['Qty'],
                item_name=row['Task_Details'],
                delivery_type=delivery_type.name,
                service_type=service_type.name,
                delivery_status=ServiceStatus.PENDING.name,
                driver_notes=row['Driver_Notes'],
                proof_of_delivery='initial upload'.encode('utf8')
            ))
        delivery_data.bulk_push_to_database(list_of_deliveries)

    except ValidationError:
        raise invalid_data_error


@router.get("", status_code=200, summary="Fetch all delivery data.", description="This endpoint retrieves all delivery data from the database.", responses={HTTP_204_NO_CONTENT: {"description": strings.GENERIC_NO_CONTENT}})
def fetch_all_delivery() -> list[Delivery]:
    """
    Example:
    ```
    HTTP GET /deliveries
    ```
    """
    delivery_list: list[Delivery] = delivery_data.pull_from_database()
    if (len(delivery_list) == 0):
        return Response(status_code=204)
    return delivery_list


@router.get("/{delivery_id}", status_code=200, summary="Fetch data for a single delivery.", description="This endpoint retrieves data for a specific delivery based on its unique ID.", responses={HTTP_404_NOT_FOUND: {"description": strings.GENERIC_DATA_NOT_FOUND_ERROR}})
def fetch_one_delivery(delivery_id: int) -> Delivery:
    """
    Args:
        delivery_id (int): The ID of the delivery to retrieve.
    Example:
    ```
    HTTP GET /deliveries/1
    ```
    """
    not_found_error: HTTPException = HTTPException(
        status_code=HTTP_404_NOT_FOUND, detail=strings.GENERIC_DATA_NOT_FOUND_ERROR)
    delivery_list: list[Delivery] = delivery_data.pull_from_database()
    for delivery in delivery_list:
        if (int(delivery.delivery_id) == delivery_id):
            return delivery
    raise not_found_error


@router.put("/{delivery_id}", status_code=202, summary="Update delivery data.", description="This endpoint allows you to update delivery data based on its unique ID.", responses={HTTP_404_NOT_FOUND: {"description": strings.GENERIC_DATA_NOT_FOUND_ERROR}})
def update_delivery(delivery_id: int, updated_data: Delivery) -> None:
    """
    Args:
        delivery_id (int): The ID of the delivery to update.
        updated_data (Delivery): The updated delivery data.
    Example:
    ```
    HTTP PUT /deliveries/1
    {
        "delivery_id": 90045,
        "route_id": "FLNC",
        "receipient_name": "John Doe",
        "receipient_phone": "555-555-5555",
        "address_line_1": "123 Main St",
        "address_line_2": "",
        "receipient_city": "New York",
        "receipient_state": "NY",
        "receipient_zip_code": 12345,
        "receipient_country": "USA",
        "quantity": 2,
        "item_name": "folding table",
        "delivery_type": "DELIVERY",
        "service_type": "WHITE_GLOVES",
        "delivery_status": "DELIVERED",
        "driver_notes": "No special notes",
        "proof_of_delivery": "cHJvb2ZfZGF0YV9oZXJl"  // Raw bytea data
    }

    ```
    """
    not_found_error: HTTPException = HTTPException(
        status_code=HTTP_404_NOT_FOUND, detail=strings.GENERIC_DATA_NOT_FOUND_ERROR)
    try:
        delivery_data.update_in_database(delivery_id, updated_data)
    except Exception:
        raise not_found_error


@router.delete("/{delivery_id}", status_code=200, summary="Delete a delivery.", description="This endpoint allows you to delete a specific delivery based on its unique ID.", responses={HTTP_404_NOT_FOUND: {"description": strings.GENERIC_DATA_NOT_FOUND_ERROR}})
def delete_delivery(delivery_id: int) -> None:
    """
    Args:
        delivery_id (int): The ID of the delivery to delete.

    Example:
    ```
    HTTP DELETE /deliveries/1
    ```
    """
    not_found_error: HTTPException = HTTPException(
        status_code=HTTP_404_NOT_FOUND, detail=strings.GENERIC_DATA_NOT_FOUND_ERROR)
    try:
        delivery: Delivery = fetch_one_delivery(delivery_id)
        delete_route(delivery.route_id)
        delivery_data.remove_from_database(delivery_id)
    except Exception:
        raise not_found_error
