"use client";

import { useMemo, useState } from "react";
import { Check, ChevronsUpDown } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import {
  Popover,
  PopoverContent,
  PopoverTrigger,
} from "@/components/ui/popover";
import {
  Command,
  CommandEmpty,
  CommandInput,
  CommandItem,
  CommandList,
} from "@/components/ui/command";
import { getAllDistricts, getUpazilasByDistrict } from "@/lib/bangladesh";
import { cn } from "@/lib/utils";

export type ShippingFormFields = {
  firstName: string;
  lastName: string;
  address: string;
  city: string;
  postalCode: string;
  upazila: string;
  district: string;
  phone: string;
  email: string;
  comment: string;
};

export type ShippingFieldErrors = Partial<
  Record<keyof ShippingFormFields, string>
>;

export const INITIAL_SHIPPING: ShippingFormFields = {
  firstName: "",
  lastName: "",
  address: "",
  city: "",
  postalCode: "",
  upazila: "",
  district: "",
  phone: "",
  email: "",
  comment: "",
};

export function LocationCombobox({
  label,
  value,
  placeholder,
  options,
  disabled,
  error,
  onChange,
}: {
  label: string;
  value: string;
  placeholder: string;
  options: string[];
  disabled?: boolean;
  error?: string;
  onChange: (value: string) => void;
}) {
  const [open, setOpen] = useState(false);
  return (
    <div className="flex flex-col gap-2">
      <Label>
        {label} <span className="text-destructive">*</span>
      </Label>
      <Popover open={open} onOpenChange={setOpen}>
        <PopoverTrigger
          render={
            <Button
              type="button"
              variant="outline"
              role="combobox"
              aria-expanded={open}
              aria-invalid={Boolean(error)}
              disabled={disabled}
              className="w-full justify-between font-normal"
            />
          }
        >
          {value || placeholder}
          <ChevronsUpDown data-icon="inline-end" className="opacity-50" />
        </PopoverTrigger>
        <PopoverContent className="w-(--anchor-width) p-0">
          <Command>
            <CommandInput placeholder={`Search ${label.toLowerCase()}...`} />
            <CommandList>
              <CommandEmpty>No match found.</CommandEmpty>
              {options.map((option) => (
                <CommandItem
                  key={option}
                  value={option}
                  onSelect={() => {
                    onChange(option);
                    setOpen(false);
                  }}
                >
                  {option}
                  <Check
                    className={cn(
                      "ml-auto",
                      value === option ? "opacity-100" : "opacity-0",
                    )}
                  />
                </CommandItem>
              ))}
            </CommandList>
          </Command>
        </PopoverContent>
      </Popover>
      {error && (
        <p className="text-sm text-destructive" role="alert">
          {error}
        </p>
      )}
    </div>
  );
}

export default function CheckoutShippingForm({
  values,
  onChange,
  errors = {},
}: {
  values: ShippingFormFields;
  onChange: (v: ShippingFormFields) => void;
  errors?: ShippingFieldErrors;
}) {
  const districts = useMemo(
    () => getAllDistricts().map((district) => district.name),
    [],
  );
  const districtId = getAllDistricts().find(
    (district) => district.name === values.district,
  )?.id;
  const upazilas = useMemo(
    () =>
      districtId
        ? getUpazilasByDistrict(districtId).map((upazila) => upazila.name)
        : [],
    [districtId],
  );
  function set<K extends keyof ShippingFormFields>(
    key: K,
    value: ShippingFormFields[K],
  ) {
    onChange({ ...values, [key]: value });
  }
  const field = (key: keyof ShippingFormFields) =>
    errors[key] && (
      <p className="text-sm text-destructive" role="alert">
        {errors[key]}
      </p>
    );

  return (
    <section className="mb-4 w-full rounded-xl border bg-background p-6">
      <div className="mb-6">
        <h2 className="text-xl font-semibold">Shipping & Billing</h2>
        <p className="mt-1 text-sm text-muted-foreground">
          Enter your shipping and billing information.
        </p>
      </div>
      <div className="flex flex-col gap-6">
        <div className="grid gap-5 md:grid-cols-2">
          {(["firstName", "lastName"] as const).map((key) => (
            <div key={key} className="flex flex-col gap-2">
              <Label htmlFor={key}>
                {key === "firstName" ? "First Name" : "Last Name"}{" "}
                <span className="text-destructive">*</span>
              </Label>
              <Input
                id={key}
                value={values[key]}
                aria-invalid={Boolean(errors[key])}
                onChange={(e) => set(key, e.target.value)}
              />
              {field(key)}
            </div>
          ))}
        </div>
        <div className="flex flex-col gap-2">
          <Label htmlFor="address">
            Address <span className="text-destructive">*</span>
          </Label>
          <Input
            id="address"
            value={values.address}
            aria-invalid={Boolean(errors.address)}
            onChange={(e) => set("address", e.target.value)}
          />
          {field("address")}
        </div>
        <div className="grid gap-5 md:grid-cols-2">
          <LocationCombobox
            label="District"
            value={values.district}
            placeholder="Select district"
            options={districts}
            error={errors.district}
            onChange={(value) =>
              onChange({ ...values, district: value, upazila: "" })
            }
          />
          <LocationCombobox
            label="Thana / Upazila"
            value={values.upazila}
            placeholder="Select thana / upazila"
            options={upazilas}
            disabled={!values.district}
            error={errors.upazila}
            onChange={(value) => set("upazila", value)}
          />
        </div>
        <div className="grid gap-5 md:grid-cols-2">
          <div className="flex flex-col gap-2">
            <Label htmlFor="city">City</Label>
            <Input
              id="city"
              value={values.city}
              onChange={(e) => set("city", e.target.value)}
            />
          </div>
          <div className="flex flex-col gap-2">
            <Label htmlFor="postalCode">Postal Code</Label>
            <Input
              id="postalCode"
              value={values.postalCode}
              onChange={(e) => set("postalCode", e.target.value)}
            />
          </div>
        </div>
        <div className="grid gap-5 md:grid-cols-2">
          <div className="flex flex-col gap-2">
            <Label htmlFor="phone">
              Telephone <span className="text-destructive">*</span>
            </Label>
            <Input
              id="phone"
              type="tel"
              placeholder="01XXXXXXXXX"
              value={values.phone}
              aria-invalid={Boolean(errors.phone)}
              onChange={(e) => set("phone", e.target.value)}
            />
            {field("phone")}
          </div>
          <div className="flex flex-col gap-2">
            <Label htmlFor="email">
              E-Mail <span className="text-destructive">*</span>
            </Label>
            <Input
              id="email"
              type="email"
              value={values.email}
              aria-invalid={Boolean(errors.email)}
              onChange={(e) => set("email", e.target.value)}
            />
            {field("email")}
          </div>
        </div>
        <div className="flex flex-col gap-2">
          <Label htmlFor="comment">Comment</Label>
          <Textarea
            id="comment"
            placeholder="Any special requirement/instruction for us?"
            className="min-h-28 resize-none"
            value={values.comment}
            onChange={(e) => set("comment", e.target.value)}
          />
        </div>
      </div>
    </section>
  );
}
