import { api } from "@/services/api";
import type { Freight } from "@edr/types";
import {
  Box,
  Button,
  Card,
  Group,
  Stack,
  Text,
  useMantineTheme,
} from "@mantine/core";
import { useQuery } from "@tanstack/react-query";
import {
  addMonths,
  eachDayOfInterval,
  endOfMonth,
  endOfWeek,
  format,
  isSameMonth,
  isToday,
  startOfMonth,
  startOfWeek,
} from "date-fns";
import {
  Calendar as CalendarIcon,
  Check,
  ChevronLeft,
  ChevronRight,
  Package,
  Route,
  Train,
} from "lucide-react";
import React, { useMemo, useState } from "react";
import { UseFormReturn } from "react-hook-form";
import { BookingFormInputValues, BookingFormValues } from "./schema";

interface StepSchedulingProps {
  form: UseFormReturn<BookingFormInputValues, any, BookingFormValues>;
  referenceData?: Freight.BookingReferenceData;
}

interface DayData {
  day: number;
  dateString: string;
  isToday: boolean;
  isCurrentMonth: boolean;
  isSelectedDate: boolean;
  /** True when the route has at least one departure on this day. */
  hasDeparture: boolean;
}

export function StepScheduling({ form, referenceData }: StepSchedulingProps) {
  const theme = useMantineTheme();
  const [currentDate, setCurrentDate] = useState(new Date());

  const selectedDate = form.watch("scheduledDate");
  const originYardId = form.watch("originYard");
  const destinationYardId = form.watch("destinationYard");
  const cargoType = form.watch("cargoType");
  const containers = form.watch("containers");
  const cargoTypePath = form.watch("cargoTypePath");
  const cargoWeight = form.watch("cargoWeight");

  const originName = useMemo(
    () => referenceData?.yard.find((y) => y.id === originYardId)?.name ?? "—",
    [referenceData, originYardId],
  );

  const destinationName = useMemo(
    () =>
      referenceData?.yard.find((y) => y.id === destinationYardId)?.name ?? "—",
    [referenceData, destinationYardId],
  );

  // Day-level pool: the customer picks a DAY, not a train. We only fetch which
  // days have a departure — no capacity, no per-train detail. The batch engine
  // assigns the train later, distributing the day's pool by priority.
  const { data: availableDays } = useQuery(
    api.bookings.getAvailableDays.queryOptions({
      input: { originYardId, destinationYardId },
      enabled: !!originYardId && !!destinationYardId,
    }),
  );

  const departureDays = useMemo(
    () => new Set(availableDays ?? []),
    [availableDays],
  );

  const days = useMemo((): DayData[] => {
    const monthStart = startOfMonth(currentDate);
    const monthEnd = endOfMonth(currentDate);
    const calStart = startOfWeek(monthStart, { weekStartsOn: 1 });
    const calEnd = endOfWeek(monthEnd, { weekStartsOn: 1 });

    return eachDayOfInterval({ start: calStart, end: calEnd }).map((date) => {
      const dateString = format(date, "yyyy-MM-dd");
      return {
        day: date.getDate(),
        dateString,
        isToday: isToday(date),
        isCurrentMonth: isSameMonth(date, currentDate),
        isSelectedDate: selectedDate === dateString,
        hasDeparture: departureDays.has(dateString),
      };
    });
  }, [currentDate, departureDays, selectedDate]);

  const availableCount = useMemo(
    () => days.filter((d) => d.isCurrentMonth && d.hasDeparture).length,
    [days],
  );

  const cargoSummary = useMemo(() => {
    if (!cargoType) return "Not selected";
    if (cargoType === "container") {
      const parts = (containers ?? [])
        .filter((c) => Number(c.qty) > 0)
        .map((c) => `${c.qty} × ${c.type}`);
      return parts.length > 0 ? `Container · ${parts.join(", ")}` : "Container";
    }
    const childId = cargoTypePath?.[1];
    const commodity = referenceData?.cargo_type
      .flatMap((g) => g.children ?? [])
      .find((c) => c.id === childId);
    const weight = cargoWeight ? ` · ${cargoWeight} t` : "";
    return commodity ? `${commodity.name}${weight}` : "Bulk freight";
  }, [cargoType, containers, cargoTypePath, cargoWeight, referenceData]);

  const weeksCount = Math.ceil(days.length / 7);

  const handleDayClick = (day: DayData) => {
    if (!day.hasDeparture) return;
    // Record only the day — no specific train is chosen.
    form.setValue("scheduledDate", day.dateString, { shouldValidate: true });
  };

  return (
    <Group gap={24} align="flex-start" wrap="wrap" style={{ width: "100%" }}>
      {/* ── Calendar Card ───────────────────────────────────── */}
      <Box style={{ flex: 1, minWidth: 300 }}>
        <Card p={0} style={{ overflow: "hidden" }}>
          {/* Card header */}
          <Group
            justify="space-between"
            align="center"
            px={24}
            py={20}
            style={{
              borderBottom: `1px solid ${theme.colors["edr-border"][0]}`,
            }}
          >
            <Stack gap={3}>
              <Text fw={800} fz={18} c="edr-text.0">
                Estimated shipment date
              </Text>
              <Text fz={13} c="edr-muted">
                Planning only · pick from scheduled departures · {originName} →{" "}
                {destinationName}
              </Text>
            </Stack>
            <Group gap={10}>
              <Button
                variant="default"
                w={34}
                h={34}
                p={0}
                radius="xl"
                onClick={() => setCurrentDate((d) => addMonths(d, -1))}
              >
                <ChevronLeft size={16} />
              </Button>
              <Text fw={700} fz={14} c="edr-text.0" style={{ minWidth: 90, textAlign: "center" }}>
                {format(currentDate, "MMMM yyyy")}
              </Text>
              <Button
                variant="default"
                w={34}
                h={34}
                p={0}
                radius="xl"
                onClick={() => setCurrentDate((d) => addMonths(d, 1))}
              >
                <ChevronRight size={16} />
              </Button>
            </Group>
          </Group>

          {/* Card body */}
          <Stack gap={14} px={24} py={18}>
            <Text fz={13} fw={600} c="edr-text.0">
              {originYardId && destinationYardId
                ? `${availableCount} scheduled departure day${availableCount !== 1 ? "s" : ""} in ${format(currentDate, "MMMM")} — pick your estimated date`
                : "Select origin and destination to see scheduled departures"}
            </Text>

            {/* Weekday headers */}
            <Box
              style={{
                display: "grid",
                gridTemplateColumns: "repeat(7, 1fr)",
                gap: 6,
                paddingBottom: 8,
              }}
            >
              {["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"].map((d) => (
                <Text
                  key={d}
                  ta="center"
                  fz={10.5}
                  fw={700}
                  c="edr-muted"
                  style={{ letterSpacing: "0.06em" }}
                >
                  {d}
                </Text>
              ))}
            </Box>

            {/* Date grid */}
            <Stack gap={2}>
              {Array.from({ length: weeksCount }, (_, wi) => (
                <Box
                  key={wi}
                  style={{
                    display: "grid",
                    gridTemplateColumns: "repeat(7, 1fr)",
                    gap: 2,
                  }}
                >
                  {days.slice(wi * 7, wi * 7 + 7).map((d, di) => (
                    <DayCell key={di} day={d} onDayClick={handleDayClick} />
                  ))}
                </Box>
              ))}
            </Stack>
          </Stack>
        </Card>
      </Box>

      {/* ── Side Panel ──────────────────────────────────────── */}
      <Stack gap={20} style={{ width: 340, flexShrink: 0 }}>
        {/* Booking summary card */}
        <Card p={0} style={{ overflow: "hidden" }}>
          <Group
            justify="space-between"
            align="center"
            px={20}
            py={18}
            style={{
              borderBottom: `1px solid ${theme.colors["edr-border"][0]}`,
            }}
          >
            <Text fw={800} fz={15} c="edr-text.0">
              Booking summary
            </Text>
          </Group>

          <Stack gap={14} px={20} py={18}>
            <SummaryRow
              icon={<Route size={17} color={theme.colors["edr-muted"][0]} />}
              label="ROUTE"
              value={`${originName} → ${destinationName}`}
            />
            <SummaryRow
              icon={<Package size={17} color={theme.colors["edr-muted"][0]} />}
              label="CARGO"
              value={cargoSummary}
            />

            {selectedDate && (
              <Box
                p={14}
                style={{
                  borderRadius: theme.radius.lg,
                  backgroundColor: theme.colors["edr-soft"][0],
                }}
              >
                <Stack gap={10}>
                  <Group gap={7}>
                    <Train size={16} color={theme.colors["edr-green"][7]} />
                    <Text
                      fz={10}
                      fw={700}
                      c="edr-green.7"
                      style={{ letterSpacing: "0.08em" }}
                    >
                      ESTIMATED DATE
                    </Text>
                  </Group>
                  <Text fw={800} fz={16} c="edr-text.0">
                    {format(new Date(selectedDate + "T00:00:00"), "EEE, MMM d yyyy")}
                  </Text>
                  <Text fz={12.5} c="edr-muted">
                    A planning estimate. You'll confirm the actual shipment date
                    later when you request the operation.
                  </Text>
                </Stack>
              </Box>
            )}
          </Stack>
        </Card>

        {/* Help card */}
        <Box
          p={18}
          style={{
            borderRadius: theme.radius.xl,
            backgroundColor: theme.colors["edr-ink"][0],
          }}
        >
          <Stack gap={8}>
            <Group gap={8} align="center">
              <CalendarIcon size={18} color={theme.colors["edr-green"][5]} />
              <Text fw={700} fz={14} c="white">
                Need a different date?
              </Text>
            </Group>
            <Text fz={12.5} style={{ color: "#A7B6C2", lineHeight: 1.5 }}>
              Our freight desk can arrange charter departures for full-train loads.
            </Text>
            <Text fz={13} fw={700} c="edr-green.5" style={{ cursor: "pointer" }}>
              Contact freight desk →
            </Text>
          </Stack>
        </Box>
      </Stack>
    </Group>
  );
}

interface DayCellProps {
  day: DayData;
  onDayClick: (day: DayData) => void;
}

function DayCell({ day: d, onDayClick }: DayCellProps) {
  const theme = useMantineTheme();

  if (!d.isCurrentMonth) {
    return (
      <Box
        style={{
          height: 92,
          borderRadius: theme.radius.md,
          opacity: 0.4,
          overflow: "hidden",
          padding: "4px 6px",
          backgroundColor: "transparent",
        }}
      >
        <Text fz={14} fw={600} c="edr-muted">
          {d.day}
        </Text>
      </Box>
    );
  }

  const cellBg = d.isSelectedDate
    ? theme.colors["edr-soft"][0]
    : d.hasDeparture
      ? "#FFFFFF"
      : "transparent";

  const cellBorder = d.isSelectedDate
    ? `2px solid ${theme.colors["edr-green"][5]}`
    : d.hasDeparture
      ? `1px solid ${theme.colors["edr-border"][0]}`
      : "none";

  return (
    <Box
      onClick={() => d.hasDeparture && onDayClick(d)}
      style={{
        height: 92,
        borderRadius: theme.radius.md,
        backgroundColor: cellBg,
        border: cellBorder,
        overflow: "hidden",
        padding: "8px 10px 10px",
        display: "flex",
        flexDirection: "column",
        gap: 4,
        cursor: d.hasDeparture ? "pointer" : "default",
        transition: "all 150ms ease",
        boxShadow: d.hasDeparture && !d.isSelectedDate ? "0 1px 3px rgba(0, 0, 0, 0.05)" : "none",
      }}
      onMouseEnter={(e) => {
        if (d.hasDeparture && !d.isSelectedDate) {
          e.currentTarget.style.boxShadow = "0 4px 12px rgba(0, 0, 0, 0.1)";
          e.currentTarget.style.borderColor = theme.colors["edr-border"][0];
        }
      }}
      onMouseLeave={(e) => {
        if (d.hasDeparture && !d.isSelectedDate) {
          e.currentTarget.style.boxShadow = "0 1px 3px rgba(0, 0, 0, 0.05)";
          e.currentTarget.style.borderColor = theme.colors["edr-border"][0];
        }
      }}
    >
      {/* Day number + check icon */}
      <Group justify="space-between" align="center" style={{ flexShrink: 0 }}>
        <Stack gap={0}>
          <Text
            fz={16}
            fw={800}
            c={
              d.isToday && !d.isSelectedDate
                ? "edr-green.6"
                : d.hasDeparture
                  ? "edr-text.0"
                  : "edr-muted"
            }
          >
            {d.day}
          </Text>
          {d.isToday && !d.isSelectedDate && (
            <Text fz={9} fw={700} c="edr-green.6" style={{ letterSpacing: "0.04em" }}>
              TODAY
            </Text>
          )}
        </Stack>
        {d.isSelectedDate && (
          <Box
            style={{
              width: 24,
              height: 24,
              borderRadius: "50%",
              backgroundColor: theme.colors["edr-green"][5],
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
            }}
          >
            <Check size={14} color="white" strokeWidth={3} />
          </Box>
        )}
      </Group>

      {/* Availability marker — a single dot for days that have a departure.
          No counts or capacity are shown: it's a day-level pool. */}
      {d.hasDeparture && (
        <Box style={{ flex: 1, display: "flex", alignItems: "flex-end" }}>
          <Box
            style={{
              width: 8,
              height: 8,
              borderRadius: "50%",
              backgroundColor: theme.colors["edr-green"][5],
              boxShadow: `0 0 0 3px ${theme.colors["edr-green"][0]}`,
            }}
          />
        </Box>
      )}
    </Box>
  );
}

function SummaryRow({
  icon,
  label,
  value,
}: {
  icon: React.ReactNode;
  label: string;
  value: string;
}) {
  const theme = useMantineTheme();
  return (
    <Group gap={12} align="flex-start" wrap="nowrap">
      <Box
        w={34}
        h={34}
        style={{
          borderRadius: theme.radius.md,
          backgroundColor: theme.colors.gray[0],
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          flexShrink: 0,
        }}
      >
        {icon}
      </Box>
      <Stack gap={1} style={{ flex: 1, minWidth: 0 }}>
        <Text fz={10} fw={700} style={{ color: "#9AA8B5", letterSpacing: "0.08em" }}>
          {label}
        </Text>
        <Text fz={13} fw={600} c="edr-text.0">
          {value}
        </Text>
      </Stack>
    </Group>
  );
}
