from typing import Self
from enum import Enum
from dataclasses import dataclass
from db.dbtransactions import DBTransactions
import binascii

transaction: DBTransactions = DBTransactions()


class DeliveryType(Enum):
    DELIVERY = 0
    PICK_UP_FROM_CUST = 1
    P_AND_D_PICKUP = 2
    P_AND_D_DELIVERY = 3
    PICK_UP = 4
    DELIVERY_EVEN_EXC = 5


class ServiceType(Enum):
    WHITE_GLOVES = 0
    THRESHOLD = 1
    PICK_UP = 2
    ROOM_OF_CHOICE = 3


class ServiceStatus(Enum):
    PENDING = 0
    IN_TRANSIT = 1
    DELIVERED = 2
    CANCELLED = 3


@dataclass
class Delivery:
    """
    Data class that represents each delivery, 
    reflection of the data and how it's stored in the database.
    """
    delivery_id: int
    route_id: str
    recipient_name: str
    recipient_phone: str
    address_line_1: str
    address_line_2: str
    recipient_city: str
    recipient_state: str
    recipient_zip_code: int
    recipient_country: str
    quantity: int
    item_name: str
    delivery_type: DeliveryType
    service_type: ServiceType
    delivery_status: ServiceStatus
    driver_notes: str = None
    proof_of_delivery: bytes = None

    def pull_from_database(self) -> list[Self]:
        """
        Pull delvery data from the database.\n
        Returns - A list of items from the database 
        where each item is a Delivery object.
        """

        database_data: list[tuple] = transaction.get_data("delivery")
        transformed_data: list[Self] = []
        for delivery in database_data:
            transformed_data.append(Delivery(
                delivery[0],
                delivery[1],
                delivery[2],
                delivery[3],
                delivery[4],
                delivery[5],
                delivery[6],
                delivery[7],
                delivery[8],
                delivery[9],
                delivery[10],
                delivery[11],
                delivery[12],
                delivery[13],
                delivery[14],
                delivery[15],
                binascii.hexlify(delivery[16])
                ))
        return transformed_data

    def push_to_database(self, database_data: Self) -> None:
        """
        Push delvery data to the database, one delivery at a time.
        """
        transaction.add_data("delivery", self.convert_to_tuple(database_data))

    def bulk_push_to_database(self, database_data: list[Self]) -> None:
        string_data: list[tuple] = []
        for item in database_data:
            item.proof_of_delivery = b'initial upload'
            string_data.append(self.convert_to_tuple(item))
        transaction.bulk_add_data("delivery", string_data)

    def remove_from_database(self, delivery_id: int) -> None:
        transaction.remove_data("delivery", "deliveryid", delivery_id)

    def update_in_database(self, delivery_id: int, data: Self) -> None:
        transaction.update_data("delivery", "deliveryid",
                                delivery_id, self.transform_to_query(data))

    def transform_to_query(self, data: Self):
        return f"""
                deliveryid={data.delivery_id},
                routeid={data.route_id},
                recipientname={data.recipient_names},
                recipientphone={data.recipient_phone},
                addresline1={data.address_line_1},
                addresline2={data.address_line_2},
                recipientcity={data.recipient_city},
                recipientstate={data.recipient_state},
                recipientpostalcode={data.recipient_zip_code},
                recipientcountry={data.recipient_country},
                quantity={data.quantity},
                itemname={data.item_name},
                deliverytype={data.delivery_type},
                servicetype={data.service_type},
                deliverystatus={data.service_status},
                drivernotes={data.driver_notes},
                proofofdelivery={data.proof_of_delivery}
                   """

    def convert_to_tuple(self, data: Self) -> tuple:
        return (
            data.delivery_id,
            data.route_id,
            data.recipient_name,
            data.recipient_phone,
            data.address_line_1,
            data.address_line_2,
            data.recipient_city,
            data.recipient_state,
            data.recipient_zip_code,
            data.recipient_country,
            data.quantity,
            data.item_name,
            data.delivery_type,
            data.service_type,
            data.delivery_status,
            data.driver_notes,
            data.proof_of_delivery
        )
