"use client";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import * as React from "react";
import { ScheduleView } from "@open-mercato/ui/backend/schedule";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@open-mercato/ui/primitives/dialog";
import { CrudForm } from "@open-mercato/ui/backend/CrudForm";
import { createCrud, deleteCrud, updateCrud } from "@open-mercato/ui/backend/utils/crud";
import { createCrudFormError } from "@open-mercato/ui/backend/utils/serverErrors";
import { flash } from "@open-mercato/ui/backend/FlashMessages";
import { Button } from "@open-mercato/ui/primitives/button";
import { Input } from "@open-mercato/ui/primitives/input";
import { LoadingMessage, ErrorMessage } from "@open-mercato/ui/backend/detail";
import { useT } from "@open-mercato/shared/lib/i18n/context";
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
import { withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
import { parseAvailabilityRuleWindow } from "@open-mercato/core/modules/planner/lib/availabilitySchedule";
import { GanttChart } from "lucide-react";
const DAY_CODES = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"];
function formatDateTimeLocal(value) {
  const offset = value.getTimezoneOffset();
  const adjusted = new Date(value.getTime() - offset * 6e4);
  return adjusted.toISOString().slice(0, 16);
}
function parseDateTimeLocal(value) {
  if (!value) return null;
  const parsed = new Date(value);
  if (Number.isNaN(parsed.getTime())) return null;
  return parsed;
}
function formatDuration(minutes) {
  const clamped = Math.max(1, minutes);
  const hours = Math.floor(clamped / 60);
  const mins = clamped % 60;
  if (hours > 0 && mins > 0) return `PT${hours}H${mins}M`;
  if (hours > 0) return `PT${hours}H`;
  return `PT${mins}M`;
}
function buildAvailabilityRrule(start, end, repeat) {
  const dtStart = start.toISOString().replace(/[-:]/g, "").split(".")[0] + "Z";
  const durationMinutes = Math.max(1, Math.round((end.getTime() - start.getTime()) / 6e4));
  const duration = formatDuration(durationMinutes);
  let rule = "";
  if (repeat === "once") {
    rule = "FREQ=DAILY;COUNT=1";
  } else if (repeat === "weekly") {
    const dayCode = DAY_CODES[start.getDay()];
    rule = `FREQ=WEEKLY;BYDAY=${dayCode}`;
  } else {
    rule = "FREQ=DAILY";
  }
  return `DTSTART:${dtStart}
DURATION:${duration}
RRULE:${rule}`;
}
function normalizeExdatesInput(value) {
  const values = Array.isArray(value) ? value : [];
  return values.map((item) => parseDateTimeLocal(String(item ?? ""))).filter((item) => item !== null).map((item) => item.toISOString());
}
function formatExdatesInput(exdates) {
  return exdates.map((value) => {
    const parsed = new Date(value);
    if (Number.isNaN(parsed.getTime())) return null;
    return formatDateTimeLocal(parsed);
  }).filter((value) => value !== null);
}
function AvailabilitySchedule({
  subjectType,
  subjectId,
  labelPrefix,
  mode = "availability",
  buildScheduleItems
}) {
  const t = useT();
  const dialogRef = React.useRef(null);
  const [availabilityRules, setAvailabilityRules] = React.useState([]);
  const [availabilityLoading, setAvailabilityLoading] = React.useState(true);
  const [availabilityError, setAvailabilityError] = React.useState(null);
  const [dialogOpen, setDialogOpen] = React.useState(false);
  const [editingRule, setEditingRule] = React.useState(null);
  const [scheduleView, setScheduleView] = React.useState("week");
  const [timezone, setTimezone] = React.useState(() => Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC");
  const [range, setRange] = React.useState(() => {
    const now = /* @__PURE__ */ new Date();
    const start = new Date(now.getFullYear(), now.getMonth(), now.getDate());
    const end = new Date(start.getTime() + 6 * 24 * 60 * 60 * 1e3);
    return { start, end };
  });
  const [slotSeed, setSlotSeed] = React.useState(null);
  const refreshAvailability = React.useCallback(async () => {
    if (!subjectId) return;
    setAvailabilityLoading(true);
    setAvailabilityError(null);
    try {
      const params = new URLSearchParams({
        page: "1",
        pageSize: "100",
        subjectType,
        subjectIds: subjectId
      });
      const call = await apiCall(`/api/planner/availability?${params.toString()}`);
      const items = Array.isArray(call.result?.items) ? call.result.items : [];
      setAvailabilityRules(items);
    } catch (error) {
      const message = error instanceof Error ? error.message : t(`${labelPrefix}.availability.error.load`, "Failed to load availability.");
      setAvailabilityError(message);
    } finally {
      setAvailabilityLoading(false);
    }
  }, [labelPrefix, subjectId, subjectType, t]);
  React.useEffect(() => {
    void refreshAvailability();
  }, [refreshAvailability]);
  const scheduleItems = React.useMemo(
    () => buildScheduleItems({ availabilityRules, translate: t }),
    [availabilityRules, buildScheduleItems, t]
  );
  const ruleMap = React.useMemo(
    () => new Map(availabilityRules.map((rule) => [rule.id, rule])),
    [availabilityRules]
  );
  const availabilityLabels = React.useMemo(() => {
    const modeBase = `${labelPrefix}.${mode}`;
    const availabilityBase = `${labelPrefix}.availability`;
    const isUnavailable = mode === "unavailability";
    return {
      sectionTitle: t(`${labelPrefix}.availability.section.title`, "Availability"),
      addAction: t(
        `${modeBase}.actions.add`,
        isUnavailable ? "Add unavailability" : "Add availability"
      ),
      editTitle: t(
        `${modeBase}.form.title.edit`,
        isUnavailable ? "Edit unavailability" : "Edit availability"
      ),
      createTitle: t(
        `${modeBase}.form.title.create`,
        isUnavailable ? "Add unavailability" : "Add availability"
      ),
      createError: t(
        `${modeBase}.form.errors.create`,
        isUnavailable ? "Failed to create unavailability." : "Failed to create availability."
      ),
      updateError: t(
        `${modeBase}.form.errors.update`,
        isUnavailable ? "Failed to update unavailability." : "Failed to update availability."
      ),
      deleteError: t(
        `${modeBase}.form.errors.delete`,
        isUnavailable ? "Failed to delete unavailability." : "Failed to delete availability."
      ),
      createdFlash: t(
        `${modeBase}.form.flash.created`,
        isUnavailable ? "Unavailability created." : "Availability created."
      ),
      updatedFlash: t(
        `${modeBase}.form.flash.updated`,
        isUnavailable ? "Unavailability updated." : "Availability updated."
      ),
      deletedFlash: t(
        `${modeBase}.form.flash.deleted`,
        isUnavailable ? "Unavailability deleted." : "Availability deleted."
      ),
      startLabel: t(`${availabilityBase}.form.fields.start`, "Start"),
      endLabel: t(`${availabilityBase}.form.fields.end`, "End"),
      repeatLabel: t(`${availabilityBase}.form.fields.repeat`, "Repeat"),
      timezoneLabel: t(`${availabilityBase}.form.fields.timezone`, "Timezone"),
      exdatesLabel: t(`${modeBase}.form.fields.exdates`, "Exceptions"),
      exdatesHelp: t(
        `${modeBase}.form.fields.exdates.help`,
        isUnavailable ? "Exclude these dates from unavailability." : "Exclude these dates from availability."
      ),
      exdatesAdd: t(`${availabilityBase}.form.fields.exdates.add`, "Add exception"),
      exdatesRemove: t(`${availabilityBase}.form.fields.exdates.remove`, "Remove"),
      invalidDates: t(`${availabilityBase}.form.errors.invalidDates`, "Start and end times are required."),
      invalidRange: t(`${availabilityBase}.form.errors.invalidRange`, "End time must be after start."),
      submitCreate: t(`${availabilityBase}.form.actions.create`, "Create"),
      submitSave: t(`${availabilityBase}.form.actions.save`, "Save")
    };
  }, [labelPrefix, mode, t]);
  const scheduleLoading = availabilityLoading;
  const scheduleError = availabilityError;
  const repeatOptions = React.useMemo(() => [
    { value: "once", label: t(`${labelPrefix}.availability.repeat.once`, "Once") },
    { value: "daily", label: t(`${labelPrefix}.availability.repeat.daily`, "Daily") },
    { value: "weekly", label: t(`${labelPrefix}.availability.repeat.weekly`, "Weekly") }
  ], [labelPrefix, t]);
  const availabilityFields = React.useMemo(() => [
    {
      id: "startAt",
      label: availabilityLabels.startLabel,
      type: "custom",
      component: ({ value, setValue }) => /* @__PURE__ */ jsx(
        Input,
        {
          type: "datetime-local",
          value: typeof value === "string" ? value : "",
          onChange: (event) => setValue(event.target.value)
        }
      )
    },
    {
      id: "endAt",
      label: availabilityLabels.endLabel,
      type: "custom",
      component: ({ value, setValue }) => /* @__PURE__ */ jsx(
        Input,
        {
          type: "datetime-local",
          value: typeof value === "string" ? value : "",
          onChange: (event) => setValue(event.target.value)
        }
      )
    },
    {
      id: "repeat",
      label: availabilityLabels.repeatLabel,
      type: "select",
      options: repeatOptions.map((option) => ({ value: option.value, label: option.label }))
    },
    {
      id: "timezone",
      label: availabilityLabels.timezoneLabel,
      type: "text"
    },
    {
      id: "exdates",
      label: availabilityLabels.exdatesLabel,
      description: availabilityLabels.exdatesHelp,
      type: "custom",
      component: ({ value, setValue }) => {
        const list = formatExdatesInput(Array.isArray(value) ? value.map(String) : []);
        return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
          list.map((entry, index) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
            /* @__PURE__ */ jsx(Input, { type: "datetime-local", value: entry, onChange: () => {
            }, readOnly: true }),
            /* @__PURE__ */ jsx(
              Button,
              {
                type: "button",
                variant: "ghost",
                size: "sm",
                onClick: () => {
                  const next = [...list];
                  next.splice(index, 1);
                  setValue(normalizeExdatesInput(next));
                },
                children: availabilityLabels.exdatesRemove
              }
            )
          ] }, `${entry}-${index}`)),
          /* @__PURE__ */ jsx(
            Button,
            {
              type: "button",
              variant: "outline",
              size: "sm",
              onClick: () => {
                const next = [...list, formatDateTimeLocal(/* @__PURE__ */ new Date())];
                setValue(normalizeExdatesInput(next));
              },
              children: availabilityLabels.exdatesAdd
            }
          )
        ] });
      }
    }
  ], [availabilityLabels, repeatOptions]);
  const availabilityInitialValues = React.useMemo(() => {
    if (editingRule) {
      const window = parseAvailabilityRuleWindow(editingRule);
      return {
        timezone: editingRule.timezone ?? timezone,
        startAt: formatDateTimeLocal(window.startAt),
        endAt: formatDateTimeLocal(window.endAt),
        repeat: window.repeat,
        exdates: editingRule.exdates ?? []
      };
    }
    const seed = slotSeed;
    if (seed) {
      return {
        timezone,
        startAt: formatDateTimeLocal(seed.start),
        endAt: formatDateTimeLocal(seed.end),
        repeat: "once",
        exdates: []
      };
    }
    const now = /* @__PURE__ */ new Date();
    return {
      timezone,
      startAt: formatDateTimeLocal(now),
      endAt: formatDateTimeLocal(new Date(now.getTime() + 60 * 60 * 1e3)),
      repeat: "once",
      exdates: []
    };
  }, [editingRule, slotSeed, timezone]);
  const handleAvailabilitySubmit = React.useCallback(async (values) => {
    const start = parseDateTimeLocal(String(values.startAt ?? ""));
    const end = parseDateTimeLocal(String(values.endAt ?? ""));
    if (!start || !end) {
      throw createCrudFormError(availabilityLabels.invalidDates);
    }
    if (start >= end) {
      throw createCrudFormError(availabilityLabels.invalidRange);
    }
    const repeat = values.repeat ?? "once";
    const rule = buildAvailabilityRrule(start, end, repeat);
    const payload = {
      subjectType,
      subjectId,
      timezone: typeof values.timezone === "string" && values.timezone.trim().length ? values.timezone.trim() : timezone,
      rrule: rule,
      exdates: normalizeExdatesInput(values.exdates)
    };
    if (editingRule) {
      const headers = buildOptimisticLockHeader(editingRule.updatedAt ?? editingRule.updated_at ?? null);
      await withScopedApiRequestHeaders(headers, () => updateCrud("planner/availability", { id: editingRule.id, ...payload }, {
        errorMessage: availabilityLabels.updateError
      }));
      flash(availabilityLabels.updatedFlash, "success");
    } else {
      await createCrud("planner/availability", payload, {
        errorMessage: availabilityLabels.createError
      });
      flash(availabilityLabels.createdFlash, "success");
    }
    setDialogOpen(false);
    setEditingRule(null);
    setSlotSeed(null);
    await refreshAvailability();
  }, [availabilityLabels, editingRule, refreshAvailability, subjectId, subjectType, timezone]);
  const handleAvailabilityDelete = React.useCallback(async () => {
    if (!editingRule) return;
    const headers = buildOptimisticLockHeader(editingRule.updatedAt ?? editingRule.updated_at ?? null);
    await withScopedApiRequestHeaders(headers, () => deleteCrud("planner/availability", editingRule.id, {
      errorMessage: availabilityLabels.deleteError
    }));
    setDialogOpen(false);
    setEditingRule(null);
    setSlotSeed(null);
    await refreshAvailability();
  }, [availabilityLabels, editingRule, refreshAvailability]);
  const handleItemClick = React.useCallback((item) => {
    const rule = item.metadata?.rule;
    if (!rule) return;
    setEditingRule(ruleMap.get(rule.id) ?? rule);
    setSlotSeed(null);
    setDialogOpen(true);
  }, [ruleMap]);
  const handleSlotClick = React.useCallback((slot) => {
    setSlotSeed(slot);
    setEditingRule(null);
    setDialogOpen(true);
  }, []);
  const openCreateDialog = React.useCallback(() => {
    setSlotSeed(null);
    setEditingRule(null);
    setDialogOpen(true);
  }, []);
  return /* @__PURE__ */ jsxs(Fragment, { children: [
    /* @__PURE__ */ jsxs("div", { className: "rounded-xl border bg-card p-4", children: [
      /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
        /* @__PURE__ */ jsx("h2", { className: "text-lg font-semibold text-foreground", children: availabilityLabels.sectionTitle }),
        /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", onClick: openCreateDialog, children: [
          /* @__PURE__ */ jsx(GanttChart, { className: "mr-2 h-4 w-4", "aria-hidden": "true" }),
          availabilityLabels.addAction
        ] })
      ] }),
      /* @__PURE__ */ jsx("div", { className: "mt-4", children: scheduleLoading ? /* @__PURE__ */ jsx(LoadingMessage, { label: t(`${labelPrefix}.schedule.loading`, "Loading schedule...") }) : scheduleError ? /* @__PURE__ */ jsx(ErrorMessage, { label: scheduleError }) : /* @__PURE__ */ jsx(
        ScheduleView,
        {
          items: scheduleItems,
          view: scheduleView,
          range,
          timezone,
          onRangeChange: setRange,
          onViewChange: setScheduleView,
          onTimezoneChange: setTimezone,
          onItemClick: handleItemClick,
          onSlotClick: handleSlotClick
        }
      ) })
    ] }),
    /* @__PURE__ */ jsx(
      Dialog,
      {
        open: dialogOpen,
        onOpenChange: (open) => {
          if (!open) {
            setDialogOpen(false);
            setEditingRule(null);
            setSlotSeed(null);
          }
        },
        children: /* @__PURE__ */ jsxs(
          DialogContent,
          {
            ref: dialogRef,
            onKeyDown: (event) => {
              if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
                const form = dialogRef.current?.querySelector("form");
                if (form instanceof HTMLFormElement) form.requestSubmit();
              }
            },
            children: [
              /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: editingRule ? availabilityLabels.editTitle : availabilityLabels.createTitle }) }),
              /* @__PURE__ */ jsx(
                CrudForm,
                {
                  embedded: true,
                  fields: availabilityFields,
                  initialValues: availabilityInitialValues,
                  optimisticLockUpdatedAt: editingRule?.updatedAt ?? editingRule?.updated_at ?? null,
                  submitLabel: editingRule ? availabilityLabels.submitSave : availabilityLabels.submitCreate,
                  onSubmit: handleAvailabilitySubmit,
                  onDelete: editingRule ? handleAvailabilityDelete : void 0,
                  deleteVisible: Boolean(editingRule)
                }
              )
            ]
          }
        )
      }
    )
  ] });
}
export {
  AvailabilitySchedule
};
//# sourceMappingURL=AvailabilitySchedule.js.map
