import { useEffect, useState } from "react";
import { supabase } from "@/lib/supabase";
import { canonicalOptionLabel, dedupeOptions, normalizeOptionKey } from "@/lib/optionUtils";
import {
  BUS as FALLBACK_BUS,
  BU_CM as FALLBACK_BU_CM,
  CLIENTES as FALLBACK_CLIENTES,
  MARCAS as FALLBACK_MARCAS,
  STATUS as FALLBACK_STATUS,
  type Status,
} from "@/data/lists";

type AppListRow = {
  category: string | null;
  value: string | null;
  label: string | null;
  sort_order: number | null;
  is_active: boolean | null;
};

export type AppLists = {
  clientes: string[];
  marcas: string[];
  bus: string[];
  buCm: Record<string, string>;
  status: Status[];
};

const FALLBACK_LISTS: AppLists = {
  clientes: FALLBACK_CLIENTES,
  marcas: FALLBACK_MARCAS,
  bus: FALLBACK_BUS,
  buCm: FALLBACK_BU_CM,
  status: [...FALLBACK_STATUS],
};

let listeners: Array<() => void> = [];
let cache: AppLists = FALLBACK_LISTS;
let loading = false;
let initialized = false;
let errorMessage: string | null = null;
let appListsRealtimeChannel: ReturnType<typeof supabase.channel> | null = null;
let realtimeRefreshTimeout: ReturnType<typeof setTimeout> | null = null;
let activeHookInstances = 0;

function notify() {
  listeners.forEach((listener) => listener());
}

function uniqOptions(values: string[]) {
  return dedupeOptions(values);
}

function cleanCountryOptions(values: string[]) {
  const fallbackByKey = new Map(
    FALLBACK_BUS.map((country) => [normalizeOptionKey(country), country]),
  );

  return dedupeOptions(values)
    .map((value) => fallbackByKey.get(normalizeOptionKey(value)) || canonicalOptionLabel(value))
    .filter((value): value is string => Boolean(value));
}

function normalizeCategory(value: string | null | undefined) {
  return String(value || "")
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .toLowerCase()
    .trim();
}

function canonicalCategory(value: string | null | undefined) {
  const category = normalizeCategory(value);

  if (["client", "clients", "cliente", "clientes"].includes(category)) return "client";
  if (["brand", "brands", "marca", "marcas"].includes(category)) return "brand";
  if (
    ["country", "countries", "pais", "paises", "bu", "business_unit", "business unit"].includes(
      category,
    )
  ) {
    return "country";
  }
  if (["status", "estatus", "estado", "estados"].includes(category)) return "status";
  if (
    ["country_manager", "country manager", "cm", "bu_cm", "bu cm", "manager", "managers"].includes(
      category,
    )
  ) {
    return "country_manager";
  }

  return category;
}

function rowDisplay(row: AppListRow) {
  return canonicalOptionLabel(String(row.label || row.value || ""));
}

function buildLists(rows: AppListRow[]): AppLists {
  const clientes: string[] = [];
  const marcas: string[] = [];
  const bus: string[] = [];
  const status: string[] = [];
  const dynamicBuCm: Record<string, string> = {};

  for (const row of rows) {
    if (row.is_active === false) continue;

    const category = canonicalCategory(row.category);
    const display = rowDisplay(row);
    const value = canonicalOptionLabel(String(row.value || ""));

    if (!display && !value) continue;

    if (category === "client") clientes.push(display || value);
    if (category === "brand") marcas.push(display || value);
    if (category === "country") bus.push(display || value);
    if (category === "status") status.push(display || value);

    if (category === "country_manager" && value) {
      const manager = display || value;
      if (manager && manager !== value) {
        dynamicBuCm[value] = manager;
      }
    }
  }

  return {
    clientes: clientes.length ? uniqOptions(clientes) : uniqOptions(FALLBACK_LISTS.clientes),
    marcas: marcas.length ? uniqOptions(marcas) : uniqOptions(FALLBACK_LISTS.marcas),
    bus: bus.length ? cleanCountryOptions(bus) : uniqOptions(FALLBACK_LISTS.bus),
    buCm: bus.length ? dynamicBuCm : { ...FALLBACK_LISTS.buCm },
    status: (status.length ? uniqOptions(status) : uniqOptions(FALLBACK_LISTS.status)) as Status[],
  };
}

function setError(message: string | null) {
  errorMessage = message;
  notify();
}

export async function loadAppLists() {
  loading = true;
  setError(null);
  notify();

  try {
    const { data, error } = await supabase
      .from("tablero_cdc_app_lists")
      .select("category, value, label, sort_order, is_active")
      .eq("is_active", true)
      .order("category", { ascending: true })
      .order("sort_order", { ascending: true })
      .order("label", { ascending: true });

    if (error) throw error;

    cache = buildLists((data || []) as AppListRow[]);
    initialized = true;
  } catch (error) {
    console.error("Error cargando listas desde Supabase:", error);
    errorMessage =
      error instanceof Error
        ? error.message
        : "No se pudieron cargar los desplegables desde Supabase.";
    cache = FALLBACK_LISTS;
  } finally {
    loading = false;
    notify();
  }
}

function scheduleRealtimeRefresh() {
  if (realtimeRefreshTimeout) {
    clearTimeout(realtimeRefreshTimeout);
  }

  realtimeRefreshTimeout = setTimeout(() => {
    realtimeRefreshTimeout = null;

    if (!loading) {
      void loadAppLists();
    }
  }, 350);
}

function startAppListsRealtime() {
  if (appListsRealtimeChannel) return;

  appListsRealtimeChannel = supabase
    .channel("tablero-cdc-app-lists")
    .on("postgres_changes", { event: "*", schema: "public", table: "tablero_cdc_app_lists" }, () =>
      scheduleRealtimeRefresh(),
    )
    .subscribe((status) => {
      if (status === "CHANNEL_ERROR" || status === "TIMED_OUT") {
        console.warn("Supabase Realtime no pudo suscribirse a tablero_cdc_app_lists:", status);
      }
    });
}

function stopAppListsRealtime() {
  if (realtimeRefreshTimeout) {
    clearTimeout(realtimeRefreshTimeout);
    realtimeRefreshTimeout = null;
  }

  if (!appListsRealtimeChannel) return;

  void supabase.removeChannel(appListsRealtimeChannel);
  appListsRealtimeChannel = null;
}

export function useAppLists() {
  const [, force] = useState(0);

  useEffect(() => {
    const listener = () => force((n) => n + 1);
    listeners.push(listener);
    activeHookInstances += 1;

    startAppListsRealtime();

    if (!initialized && !loading) {
      void loadAppLists();
    }

    return () => {
      listeners = listeners.filter((x) => x !== listener);
      activeHookInstances = Math.max(0, activeHookInstances - 1);

      if (activeHookInstances === 0) {
        stopAppListsRealtime();
      }
    };
  }, []);

  return {
    lists: cache,
    loading,
    error: errorMessage,
    refresh: loadAppLists,
  };
}
