"use client";

import { useState, useEffect, useRef } from "react";
import { getSupabaseClient } from "@/lib/supabase";
import { getCompanyContext } from "@/lib/company-context";
import { Plus, Trash2, Loader2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { EntradaDecimal } from "@/components/ui/campo-decimal";
import { Switch } from "@/components/ui/switch";
import { CustomSelect } from "@/components/ui/custom-select";
import { Aviso } from "@/components/ui/aviso";
import CaixaDeConfirmacao, { type Confirmacao } from "@/components/ui/caixa-de-confirmacao";
import { formatMoneyInput, parseMoneyInput } from "@/utils/formatters";

export interface ProductCombo {
  id: string;
  main_product_id: string;
  combo_product_id: string;
  title: string;
  discount_type: "percentage" | "fixed" | "none";
  discount_value: number;
  active: boolean;
  combo_product?: {
    id: string;
    name: string;
    price: number;
    image_url: string | null;
  };
}

interface Product {
  id: string;
  name: string;
  price: number;
  image_url: string | null;
}

/* O banco aceita cada produto uma vez só no Compre Junto de um item (main_product_id + combo_product_id). */
function mensagemDoErro(err: unknown, padrao: string) {
  return (err as { code?: string } | null)?.code === "23505" ? "Esse produto já está em outro combo deste item. Escolha um produto diferente." : padrao;
}

export function ProductCombos({ productId }: { productId: string }) {
  const [combos, setCombos] = useState<ProductCombo[]>([]);
  const [loading, setLoading] = useState(true);
  const [products, setProducts] = useState<Product[]>([]);
  const [saving, setSaving] = useState(false);
  /* Avisos na própria tela: a página do produto não monta a caixa de
     avisos flutuantes, e a do navegador para de aparecer depois de algumas. */
  const [erro, setErro] = useState<string | null>(null);
  const [confirmacao, setConfirmacao] = useState<Confirmacao | null>(null);
  /* Título e valor do desconto gravam quando a pessoa para de digitar (antes ia um pedido por letra). */
  const esperas = useRef(new Map<string, ReturnType<typeof setTimeout>>());
  useEffect(() => {
    const pendentes = esperas.current;
    return () => pendentes.forEach((t) => clearTimeout(t));
  }, []);

  useEffect(() => {
    fetchData();
  }, [productId]);

  async function fetchData() {
    setLoading(true);
    try {
      const supabase = getSupabaseClient();

      const {
        data: { user },
      } = await supabase.auth.getUser();

      if (!user) return;
      const ctx = await getCompanyContext(supabase, user);
      const tenantIds = ctx.tenantIds?.length ? ctx.tenantIds : [user.id];

      // Fetch combos
      const { data: combosData, error: combosError } = await supabase
        .from("product_combos")
        .select(`
          *,
          combo_product:products!combo_product_id (
            id,
            name,
            price,
            image_url
          )
        `)
        .eq("main_product_id", productId)
        .order("created_at", { ascending: true });

      if (combosError) throw combosError;

      // Fetch all products to use in select (excluding current product)
      const { data: productsData, error: productsError } = await supabase
        .from("products")
        .select("id, name, price, image_url")
        .neq("id", productId)
        .eq("active", true)
        .in("user_id", tenantIds)
        .neq("product_kind", "digital")
        .order("name");

      if (productsError) throw productsError;

      const productsList = productsData || [];
      const existingProducts = new Map(productsList.map(p => [p.id, p]));

      // Ensure products already in combos are in the list (even if inactive)
      combosData?.forEach(c => {
        if (c.combo_product && !existingProducts.has(c.combo_product_id)) {
           existingProducts.set(c.combo_product_id, c.combo_product as Product);
        }
      });

      setCombos(combosData || []);
      setProducts(Array.from(existingProducts.values()).sort((a, b) => a.name.localeCompare(b.name)));
    } catch (err) {
      console.error(err);
      setErro("Não foi possível carregar os combos deste produto.");
    } finally {
      setLoading(false);
    }
  }

  async function handleAddCombo() {
    if (products.length === 0) {
      setErro("Nenhum outro produto ativo para sugerir no combo.");
      return;
    }
    /* O combo novo nasce com um produto que ainda não está em nenhum combo deste item
       (sempre o primeiro da lista batia no que já existia e o banco recusava). */
    const usados = new Set(combos.map((c) => c.combo_product_id));
    const livre = products.find((p) => !usados.has(p.id));
    if (!livre) {
      setErro("Todos os outros produtos já estão no Compre Junto deste item.");
      return;
    }

    const newCombo: Partial<ProductCombo> = {
      main_product_id: productId,
      combo_product_id: livre.id,
      title: "Compre Junto e Economize!",
      discount_type: "percentage",
      discount_value: 10,
      active: true,
    };

    setSaving(true);
    setErro(null);
    try {
      const supabase = getSupabaseClient();
      const { data, error } = await supabase
        .from("product_combos")
        .insert(newCombo)
        .select(`
          *,
          combo_product:products!combo_product_id (
            id,
            name,
            price,
            image_url
          )
        `)
        .single();

      if (error) throw error;
      setCombos((atuais) => [...atuais, data]);
    } catch (err) {
      console.error(err);
      setErro(mensagemDoErro(err, "Não foi possível adicionar o combo. Tente de novo."));
    } finally {
      setSaving(false);
    }
  }

  async function handleUpdateCombo(id: string, updates: Partial<ProductCombo>, esperar = false) {
    setCombos((atuais) => atuais.map((c) => (c.id === id ? { ...c, ...updates } : c)));
    if (esperar) {
      const chave = `${id}:${Object.keys(updates).join(",")}`;
      clearTimeout(esperas.current.get(chave));
      esperas.current.set(
        chave,
        setTimeout(() => {
          esperas.current.delete(chave);
          void gravarCombo(id, updates);
        }, 600),
      );
      return;
    }
    await gravarCombo(id, updates);
  }

  async function gravarCombo(id: string, updates: Partial<ProductCombo>) {
    try {
      const supabase = getSupabaseClient();

      const dbUpdates = { ...updates };
      delete dbUpdates.combo_product; // remove joined property before saving

      const { error } = await supabase
        .from("product_combos")
        .update(dbUpdates)
        .eq("id", id);

      if (error) throw error;
    } catch (err) {
      console.error(err);
      setErro(mensagemDoErro(err, "Não foi possível salvar a mudança no combo. Voltamos ao que estava gravado."));
      fetchData(); // revert
    }
  }

  function handleDeleteCombo(id: string) {
    setConfirmacao({
      titulo: "Remover este combo?",
      texto: "O produto sugerido deixa de aparecer no Compre Junto desta página.",
      confirmar: "Remover",
      tom: "perigo",
      aoConfirmar: async () => {
        await removerCombo(id);
        setConfirmacao(null);
      },
    });
  }

  async function removerCombo(id: string) {
    setSaving(true);
    setErro(null);
    try {
      const supabase = getSupabaseClient();
      const { error } = await supabase
        .from("product_combos")
        .delete()
        .eq("id", id);

      if (error) throw error;
      setCombos((atuais) => atuais.filter((c) => c.id !== id));
    } catch (err) {
      console.error(err);
      setErro("Não foi possível remover o combo. Tente de novo.");
    } finally {
      setSaving(false);
    }
  }

  if (loading) {
    return (
      <div className="flex justify-center p-8">
        <Loader2 className="w-6 h-6 animate-spin text-slate-400" />
      </div>
    );
  }

  return (
    <div className="space-y-6">
      {erro ? (
        <Aviso tom="ruim" aoFechar={() => setErro(null)}>
          {erro}
        </Aviso>
      ) : null}
      <div className="flex items-center justify-between">
        <div>
          <h3 className="text-lg font-medium text-slate-800">Compre Junto (Upsell)</h3>
          <p className="text-sm text-slate-500">Ofereça descontos ao cliente comprar produtos em conjunto.</p>
        </div>
        <Button onClick={handleAddCombo} disabled={saving} size="sm" icon={<Plus size={16} />}>
          Adicionar Combo
        </Button>
      </div>

      {combos.length === 0 ? (
        <div className="text-center p-12 bg-slate-50 border border-dashed rounded-xl border-slate-200">
          <div className="w-12 h-12 bg-blue-50 text-blue-500 rounded-full flex items-center justify-center mx-auto mb-3">
            <Plus size={24} />
          </div>
          <h4 className="text-sm font-medium text-slate-700">Nenhum combo configurado</h4>
          <p className="text-xs text-slate-500 mt-1 max-w-sm mx-auto">
            Crie combos para aumentar o ticket médio da sua loja oferecendo produtos complementares com desconto.
          </p>
        </div>
      ) : (
        <div className="space-y-4">
          {combos.map((combo) => (
            <div key={combo.id} className="p-5 border border-slate-200 rounded-xl bg-white shadow-sm space-y-4 relative">
              <div className="flex items-start justify-between">
                <div className="flex-1 space-y-4">

                  <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                    <div className="space-y-1.5">
                      <label className="text-xs font-medium text-slate-500 uppercase">Produto Sugerido</label>
                      <CustomSelect
                        /* Fora da lista: o que já está nos outros combos deste item. */
                        options={products
                          .filter((p) => p.id === combo.combo_product_id || !combos.some((c) => c.id !== combo.id && c.combo_product_id === p.id))
                          .map((p) => ({
                            value: p.id,
                            label: p.name,
                            image_url: p.image_url,
                          }))}
                        value={combo.combo_product_id}
                        onChange={(val) => {
                          const p = products.find(p => p.id === val);
                          if(p) {
                             handleUpdateCombo(combo.id, {
                               combo_product_id: val,
                               combo_product: { ...p }
                             });
                          }
                        }}
                        searchable
                        placeholder="Selecione um produto..."
                      />
                    </div>

                    <div className="space-y-1.5">
                      <label className="text-xs font-medium text-slate-500 uppercase">Título (Opcional)</label>
                      <Input
                        value={combo.title || ""}
                        onChange={(e) => handleUpdateCombo(combo.id, { title: e.target.value }, true)}
                        placeholder="Ex: Leve também e economize!"
                      />
                    </div>
                  </div>

                  <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
                    <div className="space-y-1.5">
                      <label className="text-xs font-medium text-slate-500 uppercase">Tipo de Desconto</label>
                      <CustomSelect
                        options={[
                          { value: "percentage", label: "Porcentagem (%)" },
                          { value: "fixed", label: "Valor Fixo (R$)" },
                          { value: "none", label: "Sem desconto" }
                        ]}
                        value={combo.discount_type}
                        onChange={(val) => handleUpdateCombo(combo.id, { discount_type: val as ProductCombo["discount_type"] })}
                      />
                    </div>

                    {combo.discount_type !== "none" && (
                      <div className="space-y-1.5">
                        <label className="text-xs font-medium text-slate-500 uppercase">
                          Valor do Desconto
                        </label>
                        {combo.discount_type === "percentage" ? (
                          <EntradaDecimal
                            valor={combo.discount_value}
                            aoMudar={(n) => handleUpdateCombo(combo.id, { discount_value: Math.max(0, Math.min(100, n)) }, true)}
                            casas={2}
                            placeholder="10"
                          />
                        ) : (
                          <Input
                            value={formatMoneyInput(combo.discount_value)}
                            onChange={(e) => handleUpdateCombo(combo.id, { discount_value: parseMoneyInput(e.target.value) }, true)}
                            placeholder="R$ 0,00"
                          />
                        )}
                      </div>
                    )}

                    <div className="flex items-center space-x-2 pt-6">
                      <Switch
                        checked={combo.active}
                        onCheckedChange={(val) => handleUpdateCombo(combo.id, { active: val })}
                      />
                      <span className="text-sm text-slate-600">
                        {combo.active ? "Combo Ativo" : "Combo Inativo"}
                      </span>
                    </div>
                  </div>

                </div>

                <div className="ml-4 pl-4 border-l border-slate-100 flex flex-col items-end">
                   <button
                    onClick={() => handleDeleteCombo(combo.id)}
                    className="p-2 text-slate-400 hover:text-red-500 hover:bg-red-50 rounded-lg transition-colors"
                    title="Remover combo"
                   >
                     <Trash2 size={18} />
                   </button>
                </div>
              </div>
            </div>
          ))}
        </div>
      )}
      <CaixaDeConfirmacao pedido={confirmacao} ocupado={saving} aoFechar={() => setConfirmacao(null)} />
    </div>
  );
}
