from dataclasses import asdict
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo

from ports.booking_repository import BookingRepository, PermissiveBookResult
from ports.salon_repository import SalonRepository


class BookAppointmentPermissiveUseCase:
    def __init__(
        self,
        booking_repository: BookingRepository,
        salon_repository: SalonRepository,
    ):
        self._booking = booking_repository
        self._salons = salon_repository

    async def execute(
        self,
        *,
        salon_id: str,
        service_id: str,
        client_id: str,
        requested_start: dict[str, str],
        offer_id: str | None = None,
        generated_by: str = "ai",
    ) -> dict:
        salon_tz = await self._salons.get_timezone(salon_id)
        service = await self._booking.get_service_for_booking(service_id)
        if not service:
            return asdict(
                PermissiveBookResult(success=False, reason="SERVICE_NOT_FOUND")
            )

        start = self._parse_start(requested_start, salon_tz)
        duration = int(service.get("duration") or 30)
        end = start + timedelta(minutes=duration)

        stylist_id = await self._booking.pick_stylist_permissive(salon_id, service_id)
        if not stylist_id:
            return asdict(
                PermissiveBookResult(success=False, reason="NO_STYLIST_FOUND")
            )

        appointment_id = await self._booking.create_appointment(
            salon_id=salon_id,
            service_id=service_id,
            client_id=client_id,
            stylist_id=stylist_id,
            start=start,
            end=end,
            appointment_fee=float(service.get("basePrice") or 0),
            offer_id=offer_id,
            generated_by=generated_by,
        )

        return asdict(
            PermissiveBookResult(
                success=True,
                stylist_id=stylist_id,
                appointment_id=appointment_id,
            )
        )

    @staticmethod
    def _parse_start(requested_start: dict[str, str], timezone: str) -> datetime:
        date_str = requested_start["date"]
        time_str = requested_start["time"]
        local = datetime.strptime(f"{date_str} {time_str}", "%Y-%m-%d %H:%M")
        return local.replace(tzinfo=ZoneInfo(timezone))
