import { call, os } from "@orpc/server";
import { z } from "zod";
import { randomUUID } from "crypto";
import { createKV } from "@/server/lib/create-kv";

const AvailabilitySchema = z.object({
  id: z.string(),
  date: z.string(), // YYYY-MM-DD
  time: z.string(), // HH:MM
  durationMinutes: z.number().int().positive(),
  status: z.enum(["free", "reserved"]),
  reservedByBookingId: z.string().optional(),
  createdAt: z.string(),
});

export type Availability = z.output<typeof AvailabilitySchema>;

const kv = createKV<Availability>("availability");

// Minimal Owner-Prüfung über Sessions/Users KV
type Session = { id: string; userId: string; expiresAt: string; createdAt: string };
type User = { id: string; username: string; email: string; passwordHash: string; role: "customer" | "owner"; createdAt: string };
const sessionsKV = createKV<Session>("sessions");
const usersKV = createKV<User>("users");

async function assertOwner(sessionId: string): Promise<void> {
  const session = await sessionsKV.getItem(sessionId);
  if (!session) throw new Error("Invalid session");
  if (new Date(session.expiresAt) < new Date()) throw new Error("Session expired");
  const user = await usersKV.getItem(session.userId);
  if (!user || user.role !== "owner") throw new Error("Forbidden");
}

const create = os
  .input(
    z.object({
      sessionId: z.string(),
      date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
      time: z.string().regex(/^\d{2}:\d{2}$/),
      durationMinutes: z.number().int().positive(),
    })
  )
  .handler(async ({ input }) => {
    try {
      await assertOwner(input.sessionId);
      // Prevent duplicate slot on same date+time
      const existing = await kv.getAllItems();
      const conflict = existing.some((s) => s.date === input.date && s.time === input.time);
      if (conflict) {
        throw new Error("Es existiert bereits ein Slot zu diesem Datum und dieser Uhrzeit.");
      }
      const id = randomUUID();
      const slot: Availability = {
        id,
        date: input.date,
        time: input.time,
        durationMinutes: input.durationMinutes,
        status: "free",
        createdAt: new Date().toISOString(),
      };
      await kv.setItem(id, slot);
      return slot;
    } catch (err) {
      console.error("availability.create error", err);
      throw err;
    }
  });

const update = os
  .input(AvailabilitySchema.extend({ sessionId: z.string() }))
  .handler(async ({ input }) => {
    await assertOwner(input.sessionId);
    const { sessionId, ...rest } = input as any;
    await kv.setItem(rest.id, rest as Availability);
    return rest as Availability;
  });

const remove = os
  .input(z.object({ sessionId: z.string(), id: z.string() }))
  .handler(async ({ input }) => {
    await assertOwner(input.sessionId);
    const slot = await kv.getItem(input.id);
    if (slot && slot.status === "reserved") throw new Error("Cannot delete reserved slot");
    await kv.removeItem(input.id);
  });

const list = os.handler(async () => {
  const allSlots = await kv.getAllItems();
  
  // Filter out past slots automatically
  const today = new Date().toISOString().split("T")[0]; // YYYY-MM-DD
  const now = new Date();
  const currentTime = `${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}`;
  
  const filteredSlots = allSlots.filter(slot => {
    // Keep slots for future dates
    if (slot.date > today) return true;
    
    // For today: only keep future time slots
    if (slot.date === today) {
      return slot.time > currentTime;
    }
    
    // Remove past slots
    return false;
  });
  
  // Debug logging (commented out - uncomment if needed)
  // const statusCounts = filteredSlots.reduce((acc, slot) => {
  //   acc[slot.status] = (acc[slot.status] || 0) + 1;
  //   return acc;
  // }, {} as Record<string, number>);
  // console.log(`Availability list: ${filteredSlots.length} slots (${JSON.stringify(statusCounts)})`);
  
  return filteredSlots;
});

const get = os.input(z.string()).handler(async ({ input }) => {
  return kv.getItem(input);
});

const getByDate = os
  .input(z.string()) // YYYY-MM-DD
  .handler(async ({ input }) => {
    const all = await kv.getAllItems();
    return all.filter((s) => s.date === input);
  });

const live = {
  list: os.handler(async function* ({ signal }) {
    yield call(list, {}, { signal });
    for await (const _ of kv.subscribe()) {
      yield call(list, {}, { signal });
    }
  }),
  byDate: os
    .input(z.string())
    .handler(async function* ({ input, signal }) {
      yield call(getByDate, input, { signal });
      for await (const _ of kv.subscribe()) {
        yield call(getByDate, input, { signal });
      }
    }),
};

export const router = {
  create,
  update,
  remove,
  list,
  get,
  getByDate,
  live,
};


