"use client";

import { useMemo, useState } from "react";
import AsyncSelect from "react-select/async";

import { getPlaceDetails, PlaceDetails, searchPlaces } from "@/app/lib/places";

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

interface Props {
  label?: string;
  placeholder: string;
  value: string;
  onChange: (value: string) => void;
  /** Fires once Place Details resolves for the picked suggestion — use
   * this to auto-fill pincode / lat / long rather than `onChange`. */
  onSelect?: (details: PlaceDetails) => void;
  error?: any;
}

function debouncePromise<A extends unknown[], R>(
  fn: (...args: A) => Promise<R>,
  delayMs: number
) {
  let timer: ReturnType<typeof setTimeout>;

  return (...args: A): Promise<R> =>
    new Promise((resolve) => {
      clearTimeout(timer);
      timer = setTimeout(() => resolve(fn(...args)), delayMs);
    });
}

export default function PlaceAutocomplete({
  label,
  placeholder,
  value,
  onChange,
  onSelect,
  error,
}: Props) {
  const [resolving, setResolving] = useState(false);

  const loadOptions = useMemo(
    () =>
      debouncePromise(async (input: string): Promise<Option[]> => {
        if (input.trim().length < 2) return [];

        const predictions = await searchPlaces(input);

        return predictions.map((p) => ({ label: p.description, value: p.placeId }));
      }, 300),
    []
  );

  const handleChange = async (option: Option | null) => {
    if (!option) {
      onChange("");
      return;
    }

    onChange(option.label);

    if (!onSelect) return;

    setResolving(true);

    try {
      const details = await getPlaceDetails(option.value);

      if (details) {
        onSelect({ ...details, label: option.label });
      }
    } finally {
      setResolving(false);
    }
  };

  // The form only stores the picked label (a plain string), so there's
  // no live Option object to hand back to react-select — synthesize
  // one purely so the field displays the current value.
  const selected: Option | null = value ? { label: value, value } : null;

  return (
    <div className="mb-3">
      {label && (
        <label className="form-label fw-bold text-white">
          {label}
        </label>
      )}

      <AsyncSelect
        cacheOptions
        defaultOptions={false}
        loadOptions={loadOptions}
        value={selected}
        onChange={handleChange}
        placeholder={resolving ? "Loading location details..." : placeholder}
        isSearchable
        isClearable
        isLoading={resolving}
        noOptionsMessage={({ inputValue }) =>
          inputValue.trim().length < 2 ? "Type to search" : "No places found"
        }
        menuPortalTarget={
          typeof window !== "undefined"
            ? document.body
            : undefined
        }
        styles={{
          control: (base, state) => ({
            ...base,
            backgroundColor: "#140906",
            borderColor: state.isFocused ? "#f8c100" : "#2d1b14",
            color: "#fff",
            minHeight: "52px",
            boxShadow: "none",
            "&:hover": {
              borderColor: "#f8c100",
            },
          }),

          valueContainer: (base) => ({
            ...base,
            color: "#fff",
          }),

          input: (base) => ({
            ...base,
            color: "#fff",
          }),

          singleValue: (base) => ({
            ...base,
            color: "#fff",
          }),

          placeholder: (base) => ({
            ...base,
            color: "#9e9e9e",
          }),

          menu: (base) => ({
            ...base,
            backgroundColor: "#140906",
            border: "1px solid #2d1b14",
            zIndex: 9999,
          }),

          menuList: (base) => ({
            ...base,
            backgroundColor: "#140906",
            maxHeight: "250px",
          }),

          option: (base, state) => ({
            ...base,
            backgroundColor: state.isSelected
              ? "#f8c100"
              : state.isFocused
              ? "#2b1a12"
              : "#140906",
            color: state.isSelected ? "#120500" : "#fff",
            cursor: "pointer",
          }),

          dropdownIndicator: (base) => ({
            ...base,
            color: "#fff",
            "&:hover": {
              color: "#f8c100",
            },
          }),

          indicatorSeparator: () => ({
            display: "none",
          }),

          clearIndicator: (base) => ({
            ...base,
            color: "#fff",
          }),

          menuPortal: (base) => ({
            ...base,
            zIndex: 9999,
          }),
        }}
        theme={(theme) => ({
          ...theme,
          borderRadius: 8,
          colors: {
            ...theme.colors,
            primary: "#f8c100",
            primary25: "#2b1a12",
            neutral0: "#140906",
            neutral20: "#2d1b14",
            neutral30: "#f8c100",
            neutral80: "#ffffff",
          },
        })}
      />

      {error && (
        <div className="invalid-feedback d-block">
          {error.message}
        </div>
      )}
    </div>
  );
}
