import type { Database, Tables } from "@xtablo/shared-types";
import { Hono } from "hono";
import { createFactory } from "hono/factory";
import {
  type EventTypeConfig,
  type Exception,
  generateTimeSlots,
  getDateStringCET,
  getDayOfWeek,
  type TimeSlot,
  type WeeklyAvailability,
} from "../helpers/slots.js";
import type { BaseEnv } from "../types/app.types.js";

// import { MiddlewareManager } from "../middlewares/middleware.js";

const factory = createFactory<BaseEnv>();

const getPublicSlots = factory.createHandlers(async (c) => {
  const supabase = c.get("supabase");
  const shortUserId = c.req.param("shortUserId");
  const standardName = c.req.param("standardName");

  // Get user
  const { data: userData, error: userError } = await supabase
    .from("profiles")
    .select("*")
    .eq("short_user_id", shortUserId)
    .single();

  if (userError || !userData) {
    return c.json({ error: "User not found" }, 404);
  }

  const user = userData as Tables<"profiles">;

  // Get event type
  const { data: eventTypeData, error: eventTypeError } = await supabase
    .from("event_types")
    .select("*")
    .eq("user_id", user.id)
    .eq("standard_name", standardName)
    .is("deleted_at", null)
    .single();

  if (eventTypeError || !eventTypeData) {
    return c.json({ error: "Event type not found" }, 404);
  }

  const eventType = eventTypeData as Database["public"]["Tables"]["event_types"]["Row"];
  const eventTypeConfig = eventType.config as EventTypeConfig;

  // Get user's availabilities
  const { data: availabilitiesData, error: availabilitiesError } = await supabase
    .from("availabilities")
    .select("*")
    .eq("user_id", user.id)
    .single();

  if (availabilitiesError) {
    return c.json({ error: "Availabilities not found" }, 404);
  }

  const availabilities = availabilitiesData as Tables<"availabilities">;
  const weeklyAvailability = availabilities.availability_data as WeeklyAvailability;
  const exceptions = (availabilities.exceptions as Exception[]) || [];

  // Get existing events for the next month
  // Use CET time for availability calculations
  const now = new Date();
  const nextMonth = new Date(now);
  nextMonth.setMonth(now.getMonth() + 2);

  const { data: eventsData, error: eventsError } = await supabase
    .from("events")
    .select("*")
    .eq("created_by", user.id)
    .gte("start_date", getDateStringCET(now))
    .lte("start_date", getDateStringCET(nextMonth))
    .is("deleted_at", null);

  if (eventsError) {
    return c.json({ error: "Failed to fetch events" }, 500);
  }

  const existingEvents = eventsData as Tables<"events">[];

  // Generate slots for the next month
  const slots: TimeSlot[] = [];
  const currentDate = new Date(now);

  while (currentDate <= nextMonth) {
    const dayOfWeek = getDayOfWeek(currentDate);
    const dayAvailability = weeklyAvailability[dayOfWeek];

    if (dayAvailability) {
      const daySlots = generateTimeSlots(
        now, // Pass CET current time as first parameter
        currentDate,
        dayAvailability,
        eventTypeConfig,
        exceptions,
        existingEvents
      );
      slots.push(...daySlots);
    }

    currentDate.setDate(currentDate.getDate() + 1);
  }

  // Group slots by date for easier frontend consumption
  const slotsByDate: { [date: string]: TimeSlot[] } = {};
  slots.forEach((slot) => {
    if (!slotsByDate[slot.date]) {
      slotsByDate[slot.date] = [];
    }
    slotsByDate[slot.date].push(slot);
  });

  return c.json({
    user: { name: user.name, avatar_url: user.avatar_url },
    eventType: eventTypeConfig,
    slots: slotsByDate,
    availableSlots: slots.filter((slot) => slot.available),
  });
});

export const getPublicRouter = () => {
  const publicRouter = new Hono<BaseEnv>();

  publicRouter.get("/slots/:shortUserId/:standardName", ...getPublicSlots);

  return publicRouter;
};
