import {
  Alert,
  Box,
  Combobox,
  Group,
  Input,
  InputBase,
  Paper,
  Select,
  Switch,
  Text,
  Title,
  useCombobox,
} from "@mantine/core";
import {
  AlertTriangle,
  Check,
  CheckCircle2,
  Info,
  Loader,
  XCircle,
} from "lucide-react";
import type { ReactNode } from "react";
import { useMemo } from "react";
import type {
  ControllerRenderProps,
  FieldError as RhfFieldError,
} from "react-hook-form";
import type { BookingFormInputValues } from "./schema";
import "./field-styles.css";

// Brand tokens (kept local so the form reads consistently with the booking
// detail page and the scheduling step).
const INK = "#10202F";
const MUTED = "#6B7C8E";
const GREEN = "#0EA371";
const GREEN_DARK = "#0A6F4D";
const BORDER = "#E6ECF2";

export function OptionFieldError({ error }: { error?: { message?: string } }) {
  if (!error?.message) return null;
  return (
    <Text size="xs" c="red" mt={6}>
      {error.message}
    </Text>
  );
}

/**
 * Premium selectable option card with an icon tile, title, and description.
 * Pass `icon`/`iconBg`/`iconColor` for the leading tile, or compose freely via
 * `children` (legacy callers still work).
 */
export function OptionCard({
  selected,
  onClick,
  disabled,
  icon,
  iconBg = "#ECF6F1",
  iconColor = GREEN_DARK,
  title,
  description,
  children,
}: {
  selected: boolean;
  onClick?: () => void;
  disabled?: boolean;
  icon?: ReactNode;
  iconBg?: string;
  iconColor?: string;
  title?: ReactNode;
  description?: ReactNode;
  children?: ReactNode;
}) {
  return (
    <button
      type="button"
      onClick={onClick}
      disabled={disabled}
      style={{
        position: "relative",
        width: "100%",
        textAlign: "left",
        borderRadius: 16,
        padding: 18,
        cursor: disabled ? "not-allowed" : "pointer",
        transition: "all 150ms ease",
        border: `1.5px solid ${
          disabled ? BORDER : selected ? GREEN : BORDER
        }`,
        background: disabled
          ? "#F6F8FA"
          : selected
            ? "linear-gradient(135deg, #F4FBF7 0%, #FFFFFF 70%)"
            : "#FFFFFF",
        boxShadow: selected
          ? `0 0 0 1px ${GREEN}, 0 8px 20px rgba(14,163,113,0.10)`
          : "0 1px 2px rgba(16,24,40,0.04)",
        opacity: disabled ? 0.65 : 1,
      }}
      onMouseEnter={(e) => {
        if (!disabled && !selected) {
          e.currentTarget.style.borderColor = "#BFE3D2";
          e.currentTarget.style.boxShadow = "0 6px 16px rgba(16,24,40,0.07)";
        }
      }}
      onMouseLeave={(e) => {
        if (!disabled && !selected) {
          e.currentTarget.style.borderColor = BORDER;
          e.currentTarget.style.boxShadow = "0 1px 2px rgba(16,24,40,0.04)";
        }
      }}
    >
      {selected && !disabled && (
        <span
          style={{
            position: "absolute",
            right: 14,
            top: 14,
            display: "flex",
            height: 22,
            width: 22,
            alignItems: "center",
            justifyContent: "center",
            borderRadius: "50%",
            background: GREEN,
            boxShadow: "0 2px 6px rgba(14,163,113,0.45)",
          }}
        >
          <Check style={{ width: 13, height: 13, color: "#fff" }} strokeWidth={3} />
        </span>
      )}

      {/* Structured form (icon + title + description) */}
      {(icon || title || description) && (
        <Box>
          {icon && (
            <Box
              style={{
                marginBottom: 12,
                display: "flex",
                height: 42,
                width: 42,
                alignItems: "center",
                justifyContent: "center",
                borderRadius: 12,
                background: iconBg,
                color: iconColor,
              }}
            >
              {icon}
            </Box>
          )}
          {title && (
            <Text fz={15} fw={800} c={INK}>
              {title}
            </Text>
          )}
          {description && (
            <Text fz={12.5} c={MUTED} mt={3} style={{ lineHeight: 1.5 }}>
              {description}
            </Text>
          )}
        </Box>
      )}

      {children}
    </button>
  );
}

export function AlertBox({
  tone,
  children,
}: {
  tone: "warning" | "error" | "success" | "info";
  children: ReactNode;
}) {
  const map: Record<string, { color: string; icon: ReactNode }> = {
    warning: { color: "yellow", icon: <AlertTriangle size={16} /> },
    error: { color: "red", icon: <XCircle size={16} /> },
    success: { color: "teal", icon: <CheckCircle2 size={16} /> },
    info: { color: "blue", icon: <Info size={16} /> },
  };
  const { color, icon } = map[tone];
  return (
    <Alert color={color} icon={icon} radius="lg" fz="sm">
      {children}
    </Alert>
  );
}

export function StepLabel({ children }: { children: ReactNode }) {
  return (
    <Text
      fz={11}
      fw={700}
      tt="uppercase"
      c={MUTED}
      style={{ letterSpacing: "0.07em" }}
    >
      {children}
    </Text>
  );
}

/**
 * Card shell that wraps a step's body. Gives every step the same premium
 * surface, padding, and an optional eyebrow.
 */
export function StepCard({
  children,
  eyebrow,
}: {
  children: ReactNode;
  eyebrow?: ReactNode;
}) {
  return (
    <Paper
      radius={20}
      p={{ base: "lg", sm: 28 }}
      withBorder
      bg="white"
      style={{ borderColor: BORDER, boxShadow: "0 2px 14px rgba(16,24,40,0.04)" }}
    >
      {eyebrow}
      {children}
    </Paper>
  );
}

export function StepHeader({
  title,
  description,
  icon,
}: {
  title: string;
  description: string;
  icon?: ReactNode;
}) {
  return (
    <Group gap={14} align="flex-start" wrap="nowrap" mb={22}>
      {icon && (
        <Box
          style={{
            flexShrink: 0,
            width: 44,
            height: 44,
            borderRadius: 13,
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            background: "linear-gradient(135deg, #ECF6F1, #E4F3EC)",
            color: GREEN_DARK,
          }}
        >
          {icon}
        </Box>
      )}
      <Box>
        <Title order={3} fz={20} fw={800} c={INK} style={{ letterSpacing: "-0.01em" }}>
          {title}
        </Title>
        <Text size="sm" c={MUTED} mt={4} style={{ lineHeight: 1.5 }}>
          {description}
        </Text>
      </Box>
    </Group>
  );
}

/**
 * Shared Mantine input styling so every field in the form matches. Mantine v7's
 * `styles` prop accepts only flat properties, so interactive states (`:hover`,
 * `:focus`, `[data-combobox-selected]`…) live in `field-styles.css` and are
 * applied through `fieldClassNames` below — never as `&`-nested keys here.
 */
export const fieldStyles = {
  label: { fontWeight: 600, fontSize: 13, color: INK, marginBottom: 6 },
  input: {
    borderRadius: 12,
    minHeight: 46,
    height: 46,
    paddingTop: 0,
    paddingBottom: 0,
    fontSize: 14,
    fontWeight: 500,
    color: INK,
    borderColor: BORDER,
    background: "linear-gradient(180deg, #FFFFFF 0%, #FCFDFE 100%)",
    boxShadow: "0 1px 2px rgba(16,24,40,0.04)",
    transition:
      "border-color 130ms ease, box-shadow 130ms ease, background 130ms ease",
  },
  section: { color: MUTED },
  dropdown: {
    borderRadius: 14,
    border: `1px solid ${BORDER}`,
    boxShadow: "0 12px 32px rgba(16,24,40,0.12)",
    padding: 6,
  },
  option: {
    borderRadius: 9,
    fontSize: 13.5,
    fontWeight: 500,
    padding: "9px 10px",
  },
} as const;

/**
 * Class names carrying the field's interactive states (hover/focus ring and
 * combobox selected/active option). Pair with `fieldStyles` on every Select /
 * InputBase so the look matches and no unsupported-selector warning is logged.
 */
export const fieldClassNames = {
  input: "edrFieldInput",
  option: "edrFieldOption",
} as const;

export function SelectField({
  field,
  error,
  label,
  placeholder,
  disabled,
  data,
  leftSection,
}: {
  field: ControllerRenderProps<BookingFormInputValues>;
  error?: RhfFieldError;
  label: string;
  placeholder: string;
  disabled?: boolean;
  data: string[] | { value: string; label: string }[];
  leftSection?: ReactNode;
}) {
  return (
    <Select
      label={label}
      placeholder={placeholder}
      disabled={disabled}
      data={data}
      value={
        field.value === undefined || field.value === null || field.value === ""
          ? null
          : String(field.value)
      }
      onChange={(v) => field.onChange(v ?? "")}
      onBlur={field.onBlur}
      error={error?.message}
      allowDeselect={false}
      radius={10}
      checkIconPosition="right"
      leftSection={leftSection}
      comboboxProps={{ withinPortal: true, shadow: "md", radius: "md" }}
      styles={fieldStyles}
      classNames={fieldClassNames}
    />
  );
}

/**
 * Icon + title + description row with a trailing Switch, in a card that tints
 * green when on. Used for the cargo-handling toggles (hazardous / reefer) on the
 * Route step and per container on the Cargo step. `children` renders below the
 * row when the switch is on (e.g. a bounded quantity input).
 */
export function ToggleRow({
  icon,
  iconBg,
  iconColor,
  title,
  description,
  checked,
  onChange,
  children,
}: {
  icon: ReactNode;
  iconBg: string;
  iconColor: string;
  title: string;
  description: string;
  checked: boolean;
  onChange: (v: boolean) => void;
  children?: ReactNode;
}) {
  return (
    <Box
      px={16}
      py={13}
      style={{
        borderRadius: 14,
        border: `1.5px solid ${checked ? "#CDEBDD" : BORDER}`,
        background: checked ? "#F6FBF8" : "#fff",
        transition: "all 150ms ease",
      }}
    >
      <Group justify="space-between" align="center" wrap="nowrap">
        <Group gap={13} align="center" wrap="nowrap">
          <Box
            style={{
              width: 38,
              height: 38,
              borderRadius: 11,
              flexShrink: 0,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              background: iconBg,
              color: iconColor,
            }}
          >
            {icon}
          </Box>
          <Box>
            <Text fz={14} fw={700} c={INK}>
              {title}
            </Text>
            <Text fz={12} c={MUTED} style={{ lineHeight: 1.4 }}>
              {description}
            </Text>
          </Box>
        </Group>
        <Switch
          checked={checked}
          onChange={(e) => onChange(e.currentTarget.checked)}
          color="edr-green"
          size="md"
          style={{ flexShrink: 0 }}
        />
      </Group>
      {checked && children ? <Box mt={12}>{children}</Box> : null}
    </Box>
  );
}

/**
 * One numbered toggle per container unit in the line — tap units to mark how
 * many are hazardous/refrigerated/returning (2 hazardous → toggle 2 units on).
 * Selection fills from unit 1: tapping unit N selects 1..N, tapping a selected
 * unit N keeps 1..N-1 — the count is always derived, never free-typed, so it
 * can't exceed the line quantity.
 */
export function UnitCountToggles({
  total,
  value,
  onChange,
  label,
  activeBg,
  activeBorder,
  activeColor,
}: {
  total: number;
  value: string;
  onChange: (v: string) => void;
  label: string;
  activeBg: string;
  activeBorder: string;
  activeColor: string;
}) {
  const count = Math.min(total, Math.max(0, Math.floor(Number(value) || 0)));

  return (
    <div>
      <Text fz={12} fw={600} c="#4A5A68" mb={6}>
        {label} · {count}/{total} selected
      </Text>
      <div className="flex flex-wrap gap-2">
        {Array.from({ length: total }, (_, i) => {
          const selected = i < count;
          return (
            <button
              key={i}
              type="button"
              aria-pressed={selected}
              aria-label={`Container ${i + 1}`}
              onClick={() => onChange(String(selected ? i : i + 1))}
              className="rounded-lg"
              style={{
                minWidth: 40,
                padding: "6px 10px",
                fontSize: 12,
                fontWeight: 700,
                cursor: "pointer",
                border: `1.5px solid ${selected ? activeBorder : BORDER}`,
                background: selected ? activeBg : "#fff",
                color: selected ? activeColor : MUTED,
                transition:
                  "background 120ms ease, border-color 120ms ease, color 120ms ease",
              }}
            >
              #{i + 1}
            </button>
          );
        })}
      </div>
    </div>
  );
}

interface AsyncComboboxOption {
  value: string;
  label: string;
}

export function AsyncComboboxField({
  field,
  error,
  label,
  placeholder,
  options,
  isLoading,
  searchQuery,
  onSearchChange,
  onSelect,
  disabled,
}: {
  field: ControllerRenderProps<BookingFormInputValues>;
  error?: RhfFieldError;
  label: string;
  placeholder: string;
  options: AsyncComboboxOption[];
  isLoading?: boolean;
  searchQuery: string;
  onSearchChange: (query: string) => void;
  onSelect: (value: string) => void;
  disabled?: boolean;
}) {
  const combobox = useCombobox();

  const selectedLabel = useMemo(() => {
    return options.find((opt) => opt.value === field.value)?.label || "";
  }, [field.value, options]);

  const handleSelectOption = (val: string) => {
    onSelect(val);
    combobox.closeDropdown();
  };

  return (
    <Input.Wrapper label={label} error={error?.message} styles={fieldStyles}>
      <Combobox store={combobox} disabled={disabled} shadow="md" radius="md" withinPortal>
        <Combobox.Target>
          <InputBase
            placeholder={placeholder}
            disabled={disabled}
            radius={10}
            styles={fieldStyles}
            classNames={{ input: fieldClassNames.input }}
            value={searchQuery || selectedLabel}
            onChange={(e) => {
              onSearchChange(e.currentTarget.value);
              combobox.openDropdown();
            }}
            onFocus={() => combobox.openDropdown()}
            onBlur={() => {
              field.onBlur();
              combobox.closeDropdown();
              if (!selectedLabel) {
                onSearchChange("");
              }
            }}
            rightSection={
              isLoading ? <Loader size={14} /> : <Combobox.Chevron />
            }
          />
        </Combobox.Target>

        <Combobox.Dropdown>
          <Combobox.Options>
            {isLoading ? (
              <Combobox.Empty>Loading contracts...</Combobox.Empty>
            ) : options.length === 0 ? (
              <Combobox.Empty>No contracts found</Combobox.Empty>
            ) : (
              options.map((option) => (
                <Combobox.Option
                  key={option.value}
                  value={option.value}
                  onClick={() => handleSelectOption(option.value)}
                >
                  {option.label}
                </Combobox.Option>
              ))
            )}
          </Combobox.Options>
        </Combobox.Dropdown>
      </Combobox>
    </Input.Wrapper>
  );
}
