import { useEffect, useState } from "react";
import { Button, Card, Group, NumberInput, Stack } from "@mantine/core";

import { PageContainer, PageHeader } from "@/components/page";
import DurationField from "@/components/trainScheduling/DurationField";
import { trainSchedulingService } from "@/services/trainScheduling.service";
import { useToast } from "@/hooks/use-toast";
import type { TrainSchedulingGlobalRules } from "@/types/trainScheduling";

/**
 * Coerce an API rules object into editable form state: `numeric` columns arrive
 * as strings ("250.00") and nullable offsets arrive as null — map both to a real
 * number, or "" for blank/null so a NumberInput edits cleanly and a cleared
 * offset stays blank.
 */
function toFormState(
  rules: TrainSchedulingGlobalRules,
): Partial<Record<keyof TrainSchedulingGlobalRules, number | string>> {
  const numeric: Partial<Record<keyof TrainSchedulingGlobalRules, number | string>> = {};
  for (const [key, value] of Object.entries(rules)) {
    if (key === "id") continue;
    const num = value === "" || value == null ? "" : Number(value);
    numeric[key as keyof TrainSchedulingGlobalRules] =
      typeof num === "number" && Number.isNaN(num) ? "" : num;
  }
  return numeric;
}

export default function TrainSchedulingGlobalRulesPage() {
  const { toast } = useToast();
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  // Fields hold raw NumberInput values (number | string) while editing; coerced to Number on save.
  const [form, setForm] = useState<
    Partial<Record<keyof TrainSchedulingGlobalRules, number | string>>
  >({});

  useEffect(() => {
    void (async () => {
      try {
        const rules = await trainSchedulingService.getGlobalRules();
        setForm(toFormState(rules));
      } catch {
        toast({ title: "Failed to load train scheduling rules", variant: "destructive" });
      } finally {
        setLoading(false);
      }
    })();
    // Run once on mount only. `toast` from useToast is a fresh function every
    // render — listing it here re-fired the effect on every render, refetching
    // the rules and overwriting whatever the user was typing (values snapped
    // back to the saved defaults).
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const handleSave = async () => {
    // Every field must hold a real number — an empty box (cleared but not
    // refilled) must not silently save as 0. Collect the numeric payload and
    // reject if any value is blank or NaN.
    const fields: (keyof TrainSchedulingGlobalRules)[] = [
      "maxWagonsPerTrain",
      "importWindowLeadDays",
      "exportBookingLeadHours",
      "windowOpenHour",
      "windowCloseHour",
      "windowDurationHours",
      "docReviewMinutes",
      "paymentWindowMinutes",
    ];
    const payload: Partial<Record<keyof TrainSchedulingGlobalRules, number>> = {};
    for (const key of fields) {
      const raw = form[key];
      const num = raw === "" || raw == null ? NaN : Number(raw);
      if (!Number.isFinite(num)) {
        toast({
          title: "All fields are required — fill every value before saving.",
          variant: "destructive",
        });
        return;
      }
      payload[key] = num;
    }

    // Close offsets are optional: a blank box means "no offset" (window closes at
    // departure) and is sent as 0, which the API stores as null. A filled box is
    // sent as its minute value.
    const offsetFields: (keyof TrainSchedulingGlobalRules)[] = [
      "importCloseOffsetMinutes",
      "exportCloseOffsetMinutes",
    ];
    for (const key of offsetFields) {
      const raw = form[key];
      const num = raw === "" || raw == null ? 0 : Number(raw);
      payload[key] = Number.isFinite(num) ? num : 0;
    }

    setSaving(true);
    try {
      const updated = await trainSchedulingService.updateGlobalRules(payload);
      setForm(toFormState(updated));
      toast({ title: "Train scheduling rules saved" });
    } catch {
      toast({ title: "Failed to save rules", variant: "destructive" });
    } finally {
      setSaving(false);
    }
  };

  return (
    <PageContainer>
      <PageHeader
        title="Train scheduling rules"
        subtitle="Global limits applied when previewing and assigning bookings to trains."
      />

      {/* <Card maw={720}>
        <Stack gap="md">
          <NumberInput
            label="Max wagons per train"
            value={form.maxWagonsPerTrain ?? ""}
            onChange={(value) =>
              setForm((current) => ({ ...current, maxWagonsPerTrain: value }))
            }
            clampBehavior="none"
            allowNegative={false}
            allowDecimal
            min={1}
            disabled={loading}
          />
        </Stack>
      </Card> */}

      <Card maw={720} mt="md">
        <Stack gap="md">
          <PageHeader
            title="Booking windows"
            subtitle="Import booking-day cycle and export lead time. All times in Addis Ababa (EAT)."
          />
          <DurationField
            label="Import window lead"
            description="The single booking day opens this long before departure"
            value={form.importWindowLeadDays ?? ""}
            nativeUnit="days"
            onChange={(value) =>
              setForm((current) => ({ ...current, importWindowLeadDays: value }))
            }
            min={0}
            disabled={loading}
          />
          <DurationField
            label="Export booking lead"
            description="Export bookings are accepted first-come-first-serve starting this long before departure"
            value={form.exportBookingLeadHours ?? ""}
            nativeUnit="hours"
            onChange={(value) =>
              setForm((current) => ({ ...current, exportBookingLeadHours: value }))
            }
            min={1}
            disabled={loading}
          />
          <NumberInput
            label="Window open hour (EAT)"
            description="Local hour the booking desk opens each day (e.g. 8 = 08:00)"
            value={form.windowOpenHour ?? ""}
            onChange={(value) =>
              setForm((current) => ({ ...current, windowOpenHour: value }))
            }
            clampBehavior="none"
            allowNegative={false}
            allowDecimal
            min={0}
            max={23}
            disabled={loading}
          />
          <NumberInput
            label="Window close hour (EAT)"
            description="Local hour the booking desk shuts each day; a not-yet-full window resumes next morning at the open hour. Set equal to the open hour for a 24-hour desk."
            value={form.windowCloseHour ?? ""}
            onChange={(value) =>
              setForm((current) => ({ ...current, windowCloseHour: value }))
            }
            clampBehavior="none"
            allowNegative={false}
            allowDecimal
            min={0}
            max={23}
            disabled={loading}
          />
          <DurationField
            label="Window duration"
            description="How long the import booking window stays open"
            value={form.windowDurationHours ?? ""}
            nativeUnit="hours"
            onChange={(value) =>
              setForm((current) => ({ ...current, windowDurationHours: value }))
            }
            min={1}
            disabled={loading}
          />
          <DurationField
            label="Document review"
            description="Max staff time to accept booking documents after the window closes"
            value={form.docReviewMinutes ?? ""}
            nativeUnit="minutes"
            onChange={(value) =>
              setForm((current) => ({ ...current, docReviewMinutes: value }))
            }
            min={0}
            disabled={loading}
          />
          <DurationField
            label="Payment window"
            description="Time a selected customer has to pay before the slot expires"
            value={form.paymentWindowMinutes ?? ""}
            nativeUnit="minutes"
            onChange={(value) =>
              setForm((current) => ({ ...current, paymentWindowMinutes: value }))
            }
            min={1}
            disabled={loading}
          />
        </Stack>
      </Card>

      <Card maw={720} mt="md">
        <Stack gap="md">
          <PageHeader
            title="Booking close offset"
            subtitle="How long before departure a schedule stops accepting bookings. e.g. a 3-hour import offset closes a 17:00 departure's window at 14:00; a 1-day export offset closes a Jul-10 16:00 departure at Jul-9 16:00. Leave blank to close exactly at departure. Set separately for import and export."
          />
          <DurationField
            label="Import close offset"
            description="Import/domestic booking windows close this long before departure (blank = at departure)"
            value={form.importCloseOffsetMinutes ?? ""}
            nativeUnit="minutes"
            onChange={(value) =>
              setForm((current) => ({ ...current, importCloseOffsetMinutes: value }))
            }
            min={0}
            disabled={loading}
          />
          <DurationField
            label="Export close offset"
            description="Export booking windows close this long before departure (blank = at departure)"
            value={form.exportCloseOffsetMinutes ?? ""}
            nativeUnit="minutes"
            onChange={(value) =>
              setForm((current) => ({ ...current, exportCloseOffsetMinutes: value }))
            }
            min={0}
            disabled={loading}
          />
          <Group justify="flex-end">
            <Button loading={saving} disabled={loading} onClick={() => void handleSave()}>
              Save rules
            </Button>
          </Group>
        </Stack>
      </Card>
    </PageContainer>
  );
}
