"use client";

import { useState, useRef, useEffect } from "react";
import { createPortal } from "react-dom";
import { motion, AnimatePresence } from "framer-motion";
import { ChevronDown, Check, Search } from "lucide-react";
import { clsx } from "clsx";
import { twMerge } from "tailwind-merge";
import Image from "next/image";

interface Option {
  value: string;
  label: string;
  selected_label?: string;
  icon?: React.ComponentType<{ size?: number; className?: string }>;
  image_url?: string | null;
  description?: string;
  disabled?: boolean;
  group_header?: boolean;
  /** Aplica essa font-family so ao texto do rotulo — usada pelo seletor de
   *  tipografia do catalogo, para o nome de cada fonte aparecer nela mesma. */
  labelFontFamily?: string;
}

interface CustomSelectProps {
  options: Option[];
  value: string;
  onChange: (value: string) => void;
  placeholder?: string;
  label?: string;
  searchable?: boolean;
  disabled?: boolean;
  className?: string;
  description?: string;
  portal?: boolean;
  dropdownFullWidth?: boolean;
  forceOpenDown?: boolean;
  size?: "md" | "sm";
  showChevron?: boolean;
}

const passthroughLoader = ({ src }: { src: string }) => src;

export function CustomSelect({
  options,
  value,
  onChange,
  placeholder = "Selecione...",
  label,
  searchable = false,
  disabled = false,
  className,
  description,
  portal = true,
  dropdownFullWidth = false,
  forceOpenDown = false,
  size = "md",
  showChevron = true,
}: CustomSelectProps) {
  const [isOpen, setIsOpen] = useState(false);
  const [searchTerm, setSearchTerm] = useState("");
  const containerRef = useRef<HTMLDivElement>(null);
  const buttonRef = useRef<HTMLButtonElement>(null);
  const dropdownRef = useRef<HTMLDivElement>(null);
  const [mounted, setMounted] = useState(false);
  const [dropdownStyle, setDropdownStyle] = useState<{
    top?: number;
    bottom?: number;
    left: number;
    width: number;
    maxHeight: number;
  } | null>(null);

  const selectedOption = options.find((opt) => opt.value === value);
  const SelectedIcon = selectedOption?.icon;

  const filteredOptions = searchable
    ? options.filter((opt) =>
        opt.label.toLowerCase().includes(searchTerm.toLowerCase())
      )
    : options;

  function updateDropdownPosition() {
    const btn = buttonRef.current;
    if (!btn) return;
    const rect = btn.getBoundingClientRect();
    const margin = 8;
    const viewportW = window.innerWidth;
    const viewportH = window.innerHeight;
    const spaceBelow = viewportH - rect.bottom;
    const spaceAbove = rect.top;
    const openUp = forceOpenDown ? false : spaceBelow < 280 && spaceAbove > spaceBelow;
    const maxHeight = Math.max(220, Math.min(420, (openUp ? spaceAbove : spaceBelow) - margin * 2));
    
    /* A lista vive num portal, presa a tela. Quando o gatilho esta dentro de
       uma caixa (um modal), ela tem de caber NA CAIXA: uma lista que atravessa
       a borda do modal e pousa no fundo escurecido parece defeito de montagem.
       Fora de modal, os limites continuam sendo os da janela. */
    const caixa = btn.closest('[role="dialog"]')?.getBoundingClientRect();
    const limiteEsquerdo = caixa ? Math.max(margin, caixa.left + 4) : margin;
    const limiteDireito = caixa ? Math.min(viewportW - margin, caixa.right - 4) : viewportW - margin;
    const availableWidth = Math.max(180, limiteDireito - limiteEsquerdo);
    /* Gatilho estreito (o campo Produto do orcamento tem ~170px) fazia a lista
       herdar 280px e cortar nome de produto. Uma largura minima maior mostra o
       nome inteiro; o `min` com availableWidth mantem o celular no lugar. */
    const minDropdownWidth = Math.min(360, availableWidth);
    const calculatedWidth = Math.max(rect.width, minDropdownWidth);
    const finalWidth = dropdownFullWidth ? availableWidth : Math.min(calculatedWidth, availableWidth);

    let left = dropdownFullWidth ? limiteEsquerdo : rect.left;
    if (!dropdownFullWidth) {
      if (left + finalWidth > limiteDireito) {
        left = limiteDireito - finalWidth;
      }
      left = Math.max(left, limiteEsquerdo);
    }

    setDropdownStyle({
      left,
      width: finalWidth,
      maxHeight,
      top: openUp ? undefined : rect.bottom + margin,
      bottom: openUp ? viewportH - rect.top + margin : undefined,
    });
  }

  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      const target = event.target as Node;
      if (containerRef.current?.contains(target)) return;
      if (dropdownRef.current?.contains(target)) return;
      if (containerRef.current) {
        setIsOpen(false);
        setSearchTerm("");
      }
    };

    document.addEventListener("mousedown", handleClickOutside);
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, []);

  useEffect(() => {
    if (!isOpen) return;
    updateDropdownPosition();
    const onResize = () => updateDropdownPosition();
    const onScroll = () => updateDropdownPosition();
    window.addEventListener("resize", onResize);
    window.addEventListener("scroll", onScroll, true);
    return () => {
      window.removeEventListener("resize", onResize);
      window.removeEventListener("scroll", onScroll, true);
    };
  }, [isOpen]);

  return (
    <div className={twMerge("space-y-2", className)} ref={containerRef}>
      {label && (
        <label className="block text-sm font-medium text-gray-700">
          {label}
        </label>
      )}
      {description && (
        <p className="text-xs text-gray-500">
          {description}
        </p>
      )}
      <div className="relative">
        <button
          ref={buttonRef}
          type="button"
          onClick={() => {
            if (disabled) return;
            if (!mounted) setMounted(true);
            if (isOpen) setSearchTerm("");
            const next = !isOpen;
            setIsOpen(next);
            if (next) updateDropdownPosition();
          }}
          className={clsx(
            "w-full flex items-center justify-between rounded-2xl text-left transition-all",
            size === "sm" ? "px-3 py-1.5 text-[13px] min-h-9" : "px-4 py-2.5 min-h-11",
            "bg-white border border-[rgba(198,203,224,0.9)]",
            "focus:outline-none focus-visible:ring-2 focus-visible:ring-[rgba(10,192,214,0.28)] focus-visible:border-[rgba(10,192,214,0.9)]",
            isOpen ? "border-[rgba(10,192,214,0.9)] ring-2 ring-[rgba(10,192,214,0.16)]" : "",
            disabled ? "opacity-60 cursor-not-allowed bg-[rgba(248,249,252,0.9)]" : "cursor-pointer hover:border-[rgba(153,160,190,0.95)]"
          )}
          disabled={disabled}
        >
          <span className={clsx("flex items-center gap-2 min-w-0", !selectedOption && "text-gray-500")}>
            {selectedOption?.image_url ? (
              <Image
                src={selectedOption.image_url}
                alt=""
                width={24}
                height={24}
                sizes="24px"
                className="w-6 h-6 rounded object-cover shrink-0"
                loader={passthroughLoader}
                unoptimized
                onError={(e) => {
                  e.currentTarget.style.display = 'none';
                }}
              />
            ) : SelectedIcon ? (
              <SelectedIcon size={size === "sm" ? 14 : 16} className="text-zinc-600 shrink-0" />
            ) : null}
            <span
              className="block min-w-0 truncate"
              style={selectedOption?.labelFontFamily ? { fontFamily: selectedOption.labelFontFamily } : undefined}
            >
              {selectedOption ? selectedOption.selected_label || selectedOption.label : placeholder}
            </span>
          </span>
          {showChevron ? (
            <ChevronDown
              size={size === "sm" ? 14 : 16}
              className={clsx(
                "text-gray-400 transition-transform duration-200 shrink-0",
                isOpen && "transform rotate-180"
              )}
            />
          ) : null}
        </button>

        {mounted &&
          (portal
            ? createPortal(
                <AnimatePresence>
                  {isOpen && (
                    <motion.div
                      ref={dropdownRef}
                      data-ks-select-dropdown="true"
                      initial={{ opacity: 0, y: 6 }}
                      animate={{ opacity: 1, y: 0 }}
                      exit={{ opacity: 0, y: 6 }}
                      transition={{ duration: 0.15 }}
                      className="pointer-events-auto fixed z-[1000] bg-white border border-gray-200 rounded-2xl shadow-lg overflow-hidden flex flex-col"
                      style={{
                        left: dropdownStyle?.left ?? 0,
                        width: dropdownStyle?.width ?? 0,
                        top: dropdownStyle?.top,
                        bottom: dropdownStyle?.bottom,
                        maxHeight: dropdownStyle?.maxHeight ?? 320,
                      }}
                    >
                      {searchable && (
                        <div className="p-3 border-b border-gray-100">
                          <div className="relative">
                            <Search className="absolute left-3 top-3 text-gray-400" size={14} />
                            <input
                              type="text"
                              value={searchTerm}
                              onChange={(e) => setSearchTerm(e.target.value)}
                              placeholder="Buscar..."
                              className="w-full pl-9 pr-3 py-2 text-sm bg-gray-50 border border-gray-200 rounded-xl focus:outline-none focus:border-[rgba(76,111,255,0.9)] focus:bg-white transition-colors"
                              autoFocus
                            />
                          </div>
                        </div>
                      )}

                      <div className="overflow-y-auto scrollbar-thin scrollbar-thumb-gray-200 scrollbar-track-transparent">
                        {filteredOptions.length > 0 ? (
                          <div className="p-1.5">
                            {filteredOptions.map((option) =>
                              option.disabled ? (
                                <div
                                  key={option.value}
                                  className={clsx(
                                    "w-full px-3 py-2 text-left",
                                    option.group_header
                                      ? "text-[11px] font-bold uppercase tracking-[0.12em] text-slate-500 border-t border-[rgba(198,203,224,0.4)] first:border-t-0 mt-1 first:mt-0"
                                      : "text-sm text-gray-500"
                                  )}
                                >
                                  {option.label}
                                </div>
                              ) : (
                                <button
                                  key={option.value}
                                  type="button"
                                  onClick={() => {
                                    onChange(option.value);
                                    setIsOpen(false);
                                    setSearchTerm("");
                                  }}
                                  className={clsx(
                                    "w-full flex items-center justify-between px-3 py-2.5 text-sm rounded-xl transition-colors",
                                    value === option.value
                                      ? "bg-[rgba(10,192,214,0.08)] text-[var(--ks-color-primary-strong)] font-medium"
                                      : "text-gray-700 hover:bg-gray-100"
                                  )}
                                >
                                  <span className="flex flex-col min-w-0 text-left">
                                    <span className="flex items-start gap-3">
                                      {option.image_url ? (
                                        <Image
                                          src={option.image_url}
                                          alt=""
                                          width={32}
                                          height={32}
                                          sizes="32px"
                                          className="w-8 h-8 rounded object-cover shrink-0"
                                          loader={passthroughLoader}
                                          unoptimized
                                          onError={(e) => {
                                            e.currentTarget.style.display = "none";
                                          }}
                                        />
                                      ) : option.icon ? (
                                        <option.icon size={16} className="shrink-0" />
                                      ) : null}
                                      {/* Duas linhas em vez de corte: produtos que
                                          so mudam no fim do nome (gramatura, tipo de
                                          papel, valor) ficavam identicos na lista e
                                          davam escolha errada no orcamento.
                                          O `title` cobre o caso raro de passar de
                                          duas linhas. */}
                                      <span
                                        title={option.label}
                                        className="line-clamp-2 font-medium leading-snug"
                                        style={option.labelFontFamily ? { fontFamily: option.labelFontFamily } : undefined}
                                      >
                                        {option.label}
                                      </span>
                                    </span>
                                    {option.description && (
                                      <span className="text-xs text-gray-500 mt-1 ml-7">
                                        {option.description}
                                      </span>
                                    )}
                                  </span>
                                  {value === option.value && (
                                    <Check size={14} className="text-[var(--ks-color-primary-strong)] shrink-0" />
                                  )}
                                </button>
                              )
                            )}
                          </div>
                        ) : (
                          <div className="px-3 py-4 text-center text-sm text-gray-500">
                            Nenhuma opção encontrada
                          </div>
                        )}
                      </div>
                    </motion.div>
                  )}
                </AnimatePresence>,
                document.body
              )
            : (
                <AnimatePresence>
                  {isOpen && (
                    <motion.div
                      ref={dropdownRef}
                      data-ks-select-dropdown="true"
                      initial={{ opacity: 0, y: 6 }}
                      animate={{ opacity: 1, y: 0 }}
                      exit={{ opacity: 0, y: 6 }}
                      transition={{ duration: 0.15 }}
                      className="absolute left-0 top-[calc(100%+0.5rem)] z-[1000] w-full bg-white border border-gray-200 rounded-2xl shadow-lg overflow-hidden flex flex-col"
                      style={{ maxHeight: 320 }}
                    >
                      {searchable && (
                        <div className="p-3 border-b border-gray-100">
                          <div className="relative">
                            <Search className="absolute left-3 top-3 text-gray-400" size={14} />
                            <input
                              type="text"
                              value={searchTerm}
                              onChange={(e) => setSearchTerm(e.target.value)}
                              placeholder="Buscar..."
                              className="w-full pl-9 pr-3 py-2 text-sm bg-gray-50 border border-gray-200 rounded-xl focus:outline-none focus:border-[rgba(76,111,255,0.9)] focus:bg-white transition-colors"
                              autoFocus
                            />
                          </div>
                        </div>
                      )}

                      <div className="overflow-y-auto scrollbar-thin scrollbar-thumb-gray-200 scrollbar-track-transparent">
                        {filteredOptions.length > 0 ? (
                          <div className="p-1.5">
                            {filteredOptions.map((option) =>
                              option.disabled ? (
                                <div
                                  key={option.value}
                                  className={clsx(
                                    "w-full px-3 py-2 text-left",
                                    option.group_header
                                      ? "text-[11px] font-bold uppercase tracking-[0.12em] text-slate-500 border-t border-[rgba(198,203,224,0.4)] first:border-t-0 mt-1 first:mt-0"
                                      : "text-sm text-gray-500"
                                  )}
                                >
                                  {option.label}
                                </div>
                              ) : (
                                <button
                                  key={option.value}
                                  type="button"
                                  onClick={() => {
                                    onChange(option.value);
                                    setIsOpen(false);
                                    setSearchTerm("");
                                  }}
                                  className={clsx(
                                    "w-full flex items-center justify-between px-3 py-2.5 text-sm rounded-xl transition-colors",
                                    value === option.value
                                      ? "bg-[rgba(10,192,214,0.08)] text-[var(--ks-color-primary-strong)] font-medium"
                                      : "text-gray-700 hover:bg-gray-100"
                                  )}
                                >
                                  <span className="flex flex-col min-w-0 text-left">
                                    <span className="flex items-start gap-3">
                                      {option.image_url ? (
                                        <Image
                                          src={option.image_url}
                                          alt=""
                                          width={32}
                                          height={32}
                                          sizes="32px"
                                          className="w-8 h-8 rounded object-cover shrink-0"
                                          loader={passthroughLoader}
                                          unoptimized
                                          onError={(e) => {
                                            e.currentTarget.style.display = "none";
                                          }}
                                        />
                                      ) : option.icon ? (
                                        <option.icon size={16} className="shrink-0" />
                                      ) : null}
                                      {/* Duas linhas em vez de corte: produtos que
                                          so mudam no fim do nome (gramatura, tipo de
                                          papel, valor) ficavam identicos na lista e
                                          davam escolha errada no orcamento.
                                          O `title` cobre o caso raro de passar de
                                          duas linhas. */}
                                      <span
                                        title={option.label}
                                        className="line-clamp-2 font-medium leading-snug"
                                        style={option.labelFontFamily ? { fontFamily: option.labelFontFamily } : undefined}
                                      >
                                        {option.label}
                                      </span>
                                    </span>
                                    {option.description && (
                                      <span className="text-xs text-gray-500 mt-1 ml-7">
                                        {option.description}
                                      </span>
                                    )}
                                  </span>
                                  {value === option.value && (
                                    <Check size={14} className="text-[var(--ks-color-primary-strong)] shrink-0" />
                                  )}
                                </button>
                              )
                            )}
                          </div>
                        ) : (
                          <div className="px-3 py-4 text-center text-sm text-gray-500">
                            Nenhuma opção encontrada
                          </div>
                        )}
                      </div>
                    </motion.div>
                  )}
                </AnimatePresence>
              ))}
      </div>
    </div>
  );
}
