from dataclasses import dataclass
from datetime import datetime, timedelta
import random
import string
from typing import Dict


# Default mapping from order status to extra days
DEFAULT_STATUS_DAYS: Dict[str, int] = {
    "ORDERED": 10,
    "PROCESSING": 7,
    "TRANSIT": 3,
    "READY_FOR_DELIVERY": 1,
    "DELIVERED": 0,
}


@dataclass
class OrderEstimate:
    """
    Simple container used by OrderUtils.

    Attributes
    ----------
    order_id : str
        Generated unique order identifier.
    status : str
        Order status, e.g. ORDERED, PROCESSING, TRANSIT, READY_FOR_DELIVERY, DELIVERED.
    estimated_delivery : datetime
        Estimated delivery date/time based on status.
    """
    order_id: str
    status: str
    estimated_delivery: datetime


class OrderUtils:
    """
    Utility class to help with order IDs and delivery estimates.

    Designed to be used inside Django apps and AWS Lambda.
    """

    def __init__(self, status_days: Dict[str, int] | None = None):
        # Allow custom mapping, fall back to defaults
        self.status_days = {k.upper(): v for k, v in (status_days or DEFAULT_STATUS_DAYS).items()}

    def generate_order_id(self, prefix: str = "ORD") -> str:
        """
        Generate a unique order id like: ORD-20251119104530XXXX
        """
        ts = datetime.utcnow().strftime("%Y%m%d%H%M%S")
        rand = "".join(random.choices(string.digits, k=4))
        return f"{prefix}-{ts}{rand}"

    def estimate_delivery_by_status(self, status: str) -> datetime:
        """
        Estimate delivery date from a given status.

        Example mapping (can be overridden by status_days):
            ORDERED            -> 10 days
            PROCESSING         -> 7 days
            TRANSIT            -> 3 days
            READY_FOR_DELIVERY -> 1 day
            DELIVERED          -> 0 days
        """
        key = status.upper().replace(" ", "_")

        days = self.status_days.get(key, self.status_days["ORDERED"])
        return datetime.utcnow() + timedelta(days=days)

    def create_order_estimate(self, status: str) -> OrderEstimate:
        """
        Convenience method to generate an order id and estimated delivery
        together in one call.
        """
        order_id = self.generate_order_id()
        normalized = status.upper().replace(" ", "_")
        eta = self.estimate_delivery_by_status(normalized)

        return OrderEstimate(
            order_id=order_id,
            status=normalized,
            estimated_delivery=eta
        )
