
from __future__ import annotations
from datetime import time

from sqlalchemy.ext.asyncio import AsyncSession

from models.calendars import CalendarSlot


class SlotError(ValueError):
    pass

def _b(v):
    if isinstance(v, bool):
        return v
    s = str(v).lower()
    return s in {"1","true","t","yes","y","on"}


async def update_slot(
    sess: AsyncSession,
    slot_id: int,
    *,
    name: str | None = None,
    description: str | None = None,
    days: dict | None = None,
    time_start: time | None = None,
    time_end: time | None = None,
    cost: float | None = None,
    flexible: bool | None = None,   # NEW
):
    slot = await sess.get(CalendarSlot, slot_id)
    if not slot or slot.deleted_at is not None:
        raise SlotError("slot not found")

    if name is not None:
        slot.name = name

    if description is not None:
        slot.description = description or None

    if days is not None:
        slot.mon = _b(days.get("mon", slot.mon))
        slot.tue = _b(days.get("tue", slot.tue))
        slot.wed = _b(days.get("wed", slot.wed))
        slot.thu = _b(days.get("thu", slot.thu))
        slot.fri = _b(days.get("fri", slot.fri))
        slot.sat = _b(days.get("sat", slot.sat))
        slot.sun = _b(days.get("sun", slot.sun))

    if time_start is not None:
        slot.time_start = time_start
    if time_end is not None:
        slot.time_end = time_end

    if (time_start or time_end) and slot.time_end <= slot.time_start:
        raise SlotError("time range invalid")

    if cost is not None:
        slot.cost = cost

    # NEW: update flexible flag only if explicitly provided
    if flexible is not None:
        slot.flexible = flexible

    await sess.flush()
    return slot

async def soft_delete_slot(sess: AsyncSession, slot_id: int):
    slot = await sess.get(CalendarSlot, slot_id)
    if not slot or slot.deleted_at is not None:
        return
    from datetime import datetime, timezone
    slot.deleted_at = datetime.now(timezone.utc)
    await sess.flush()


async def get_slot(sess: AsyncSession, slot_id: int) -> CalendarSlot | None:
    return await sess.get(CalendarSlot, slot_id)

async def update_slot_description(
    sess: AsyncSession,
    slot_id: int,
    description: str | None,
) -> CalendarSlot:
    slot = await sess.get(CalendarSlot, slot_id)
    if not slot:
        raise SlotError("slot not found")
    slot.description = description or None
    await sess.flush()
    return slot
