"use client";

import { useState, useEffect, useMemo, useCallback } from "react";
import { useTranslations } from "next-intl";
import { addMinutes, differenceInMinutes, format } from "date-fns";
import { Avatar } from "@/components/ui/avatar";
import { useAuthStore } from "@/stores/auth-store";
import { cn } from "@/lib/utils";
import { fetchFreeBusy, type FreeBusySlot, isWorkingHour as isWorkingHourFn } from "@/lib/calendar-freebusy";

export interface ResourceFreeBusyEntry {
  id: string;
  name: string;
  availabilityMap: Map<number, FreeBusySlot["status"]>;
}

export interface FreeBusyViewProps {
  participants: { name?: string; email: string }[];
  startDate: Date;
  endDate: Date;
  onTimeSelect?: (start: Date, end: Date) => void;
  resources?: ResourceFreeBusyEntry[];
}

const SLOT_MINUTES = 30;
const WORK_START_HOUR = 8;
const WORK_END_HOUR = 18;

const statusColors: Record<FreeBusySlot["status"], string> = {
  free: "bg-emerald-100 dark:bg-emerald-900/40 border-emerald-200 dark:border-emerald-800",
  busy: "bg-red-100 dark:bg-red-900/40 border-red-200 dark:border-red-800",
  tentative: "bg-amber-100 dark:bg-amber-900/40 border-amber-200 dark:border-amber-800",
  unavailable: "bg-purple-100 dark:bg-purple-900/40 border-purple-200 dark:border-purple-800",
  unknown: "bg-muted border-muted-foreground/20",
};

const statusHoverColors: Record<FreeBusySlot["status"], string> = {
  free: "hover:bg-emerald-200 dark:hover:bg-emerald-800/60",
  busy: "hover:bg-red-200 dark:hover:bg-red-800/60",
  tentative: "hover:bg-amber-200 dark:hover:bg-amber-800/60",
  unavailable: "hover:bg-purple-200 dark:hover:bg-purple-800/60",
  unknown: "hover:bg-muted-foreground/20",
};

function clampToSlot(d: Date): Date {
  const clone = new Date(d);
  clone.setSeconds(0, 0);
  const mins = clone.getMinutes();
  const remainder = mins % SLOT_MINUTES;
  if (remainder !== 0) {
    clone.setMinutes(mins - remainder, 0, 0);
  }
  return clone;
}

function buildHourSlots(start: Date, end: Date): { label: string; slots: FreeBusySlot[] }[] {
  const hours: { label: string; slots: FreeBusySlot[] }[] = [];
  let cursor = clampToSlot(start);
  while (cursor < end) {
    const hourEnd = new Date(cursor);
    hourEnd.setHours(hourEnd.getHours() + 1, 0, 0, 0);
    const hourSlots: FreeBusySlot[] = [];
    let slotCursor = new Date(cursor);
    while (slotCursor < hourEnd && slotCursor < end) {
      const slotEnd = addMinutes(slotCursor, SLOT_MINUTES);
      hourSlots.push({
        start: new Date(slotCursor),
        end: slotEnd > end ? new Date(end) : slotEnd,
        status: "unknown",
      });
      slotCursor = slotEnd;
    }
    hours.push({ label: format(cursor, "HH:mm"), slots: hourSlots });
    cursor = hourEnd;
  }
  return hours;
}

function isWorkingHour(hour: number): boolean {
  return isWorkingHourFn(hour, WORK_START_HOUR, WORK_END_HOUR);
}

export function FreeBusyView({
  participants,
  startDate,
  endDate,
  onTimeSelect,
  resources = [],
}: FreeBusyViewProps) {
  const t = useTranslations("calendar");
  const client = useAuthStore((s) => s.client);
  const activeAccountId = useAuthStore((s) => s.activeAccountId);
  const [freeBusyData, setFreeBusyData] = useState<Map<string, FreeBusySlot[]> | null>(null);
  const [loading, setLoading] = useState(false);
  const [hoveredSlot, setHoveredSlot] = useState<{
    participant: string;
    slotIndex: number;
  } | null>(null);

  const hourSlots = useMemo(() => buildHourSlots(startDate, endDate), [startDate, endDate]);
  const totalHalfHourSlots = useMemo(() => {
    let c = 0;
    for (const h of hourSlots) c += h.slots.length;
    return c;
  }, [hourSlots]);

  const now = new Date();
  const showNowLine =
    now >= startDate && now <= endDate;
  const nowPositionPercent = showNowLine
    ? Math.max(0, Math.min(100, (differenceInMinutes(now, startDate) / differenceInMinutes(endDate, startDate)) * 100))
    : null;

  useEffect(() => {
    if (!client || participants.length === 0) return;
    let cancelled = false;
    setLoading(true);
    fetchFreeBusy(client, participants, startDate, endDate, activeAccountId ?? undefined)
      .then((data) => {
        if (!cancelled) {
          setFreeBusyData(data);
          setLoading(false);
        }
      })
      .catch(() => {
        if (!cancelled) setLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, [client, participants, startDate, endDate]);

  const handleSlotClick = useCallback(
    (slot: FreeBusySlot) => {
      if (slot.status === "free" && onTimeSelect) {
        onTimeSelect(new Date(slot.start), new Date(slot.end));
      }
    },
    [onTimeSelect]
  );

  const timezone = useMemo(
    () => Intl.DateTimeFormat().resolvedOptions().timeZone,
    []
  );

  if (participants.length === 0) {
    return (
      <p className="text-sm text-muted-foreground py-4 text-center">
        {t("freeBusy.no_participants")}
      </p>
    );
  }

  return (
    <div className="flex flex-col gap-2">
      <div className="flex items-center justify-between">
        <div className="text-xs text-muted-foreground">
          {t("freeBusy.timezone")}: {timezone}
        </div>
        {loading && (
          <div className="text-xs text-muted-foreground animate-pulse">
            {t("freeBusy.loading")}
          </div>
        )}
      </div>

      <div className="relative">
        <div className="overflow-auto border border-border rounded-lg">
        <div className="min-w-max" style={{ minWidth: totalHalfHourSlots * 24 + 200 }}>
          <table className="w-full border-collapse text-xs">
            <thead>
              <tr>
                <th className="sticky left-0 z-10 bg-background border-b border-r border-border px-3 py-2 text-left w-[180px] min-w-[180px]">
                  {t("participants.title")}
                </th>
                {hourSlots.map((hour, i) => (
                  <th
                    key={i}
                    colSpan={hour.slots.length}
                    className={cn(
                      "border-b border-r border-border px-1 py-2 text-center font-medium",
                      isWorkingHour(new Date(hour.slots[0]?.start).getHours())
                        ? "bg-muted/50"
                        : "bg-muted/20"
                    )}
                  >
                    {hour.label}
                  </th>
                ))}
              </tr>
            </thead>
            <tbody>
              {participants.map((p) => {
                const key = p.email.toLowerCase();
                const slots = freeBusyData?.get(key);
                return (
                  <tr key={key} className="border-b border-border">
                    <td className="sticky left-0 z-10 bg-background border-r border-border px-3 py-2">
                      <div className="flex items-center gap-2">
                        <Avatar
                          name={p.name}
                          email={p.email}
                          size="sm"
                          className="shrink-0"
                        />
                        <div className="min-w-0">
                          <div className="font-medium truncate">
                            {p.name || p.email}
                          </div>
                          {p.name && (
                            <div className="text-[10px] text-muted-foreground truncate">
                              {p.email}
                            </div>
                          )}
                        </div>
                      </div>
                    </td>
                    {hourSlots.map((hour) =>
                      hour.slots.map((hourSlot, si) => {
                        const globalSlotIndex =
                          hourSlots
                            .slice(0, hourSlots.indexOf(hour))
                            .reduce((acc, h) => acc + h.slots.length, 0) + si;

                        const slot = slots?.[globalSlotIndex];
                        const status = slot?.status ?? "unknown";
                        const isFree = status === "free";
                        const isHovered =
                          hoveredSlot?.participant === key &&
                          hoveredSlot?.slotIndex === globalSlotIndex;

                        return (
                          <td
                            key={si}
                            className={cn(
                              "border-r border-border py-1 text-center relative cursor-default transition-colors",
                              statusColors[status],
                              isFree && statusHoverColors[status],
                              isFree && "cursor-pointer",
                              isHovered && "ring-1 ring-inset ring-primary/50",
                              isWorkingHour(new Date(hourSlot.start).getHours())
                                ? ""
                                : "opacity-70"
                            )}
                            title={format(hourSlot.start, "HH:mm")}
                            onClick={() => {
                              if (!isFree) return;
                              const s = slot;
                              if (!s) return;
                              handleSlotClick(s);
                            }}
                            onMouseEnter={() =>
                              setHoveredSlot({
                                participant: key,
                                slotIndex: globalSlotIndex,
                              })
                            }
                            onMouseLeave={() => setHoveredSlot(null)}
                          >
                            {status === "free" && (
                              <span className="block w-full h-full">&nbsp;</span>
                            )}
                          </td>
                        );
                      })
                    )}
                  </tr>
                );
              })}
              {resources.map((res) => (
                <tr key={`res-${res.id}`} className="border-b border-border">
                  <td className="sticky left-0 z-10 bg-background border-r border-border px-3 py-2">
                    <div className="flex items-center gap-2">
                      <div className="w-6 h-6 rounded bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center shrink-0">
                        <span className="text-[10px] font-bold text-blue-600 dark:text-blue-400">
                          R
                        </span>
                      </div>
                      <div className="min-w-0">
                        <div className="font-medium truncate text-sm">
                          {res.name}
                        </div>
                      </div>
                    </div>
                  </td>
                  {hourSlots.map((hour) =>
                    hour.slots.map((hourSlot, si) => {
                      const globalSlotIndex =
                        hourSlots
                          .slice(0, hourSlots.indexOf(hour))
                          .reduce((acc, h) => acc + h.slots.length, 0) + si;

                      const status = res.availabilityMap.get(globalSlotIndex) ?? "unknown";
                      const isFree = status === "free";

                      return (
                        <td
                          key={si}
                          className={cn(
                            "border-r border-border py-1 text-center relative cursor-default transition-colors",
                            statusColors[status],
                            isFree && "cursor-pointer",
                            isWorkingHour(new Date(hourSlot.start).getHours())
                              ? ""
                              : "opacity-70"
                          )}
                          title={`${res.name} - ${format(hourSlot.start, "HH:mm")}`}
                        >
                          {status === "free" && (
                            <span className="block w-full h-full">&nbsp;</span>
                          )}
                        </td>
                      );
                    })
                  )}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>

      {showNowLine && nowPositionPercent !== null && (
        <div
          className="absolute pointer-events-none z-20"
          style={{
            left: `calc(180px + ${nowPositionPercent}% * (1 - 180px / ${totalHalfHourSlots * 24 + 200}))`,
          }}
        />
      )}
      </div>

      <div className="flex items-center gap-3 text-xs text-muted-foreground mt-1">
        <span className="inline-flex items-center gap-1">
          <span className="w-3 h-3 rounded border border-emerald-200 dark:border-emerald-800 bg-emerald-100 dark:bg-emerald-900/40" />
          {t("freeBusy.free")}
        </span>
        <span className="inline-flex items-center gap-1">
          <span className="w-3 h-3 rounded border border-red-200 dark:border-red-800 bg-red-100 dark:bg-red-900/40" />
          {t("freeBusy.busy")}
        </span>
        <span className="inline-flex items-center gap-1">
          <span className="w-3 h-3 rounded border border-amber-200 dark:border-amber-800 bg-amber-100 dark:bg-amber-900/40" />
          {t("freeBusy.tentative")}
        </span>
        <span className="inline-flex items-center gap-1">
          <span className="w-3 h-3 rounded border border-purple-200 dark:border-purple-800 bg-purple-100 dark:bg-purple-900/40" />
          {t("freeBusy.unavailable")}
        </span>
        <span className="inline-flex items-center gap-1">
          <span className="w-3 h-3 rounded border border-muted-foreground/20 bg-muted" />
          {t("freeBusy.unknown")}
        </span>
      </div>
    </div>
  );
}
