import React, { useEffect, useRef, useState } from "react";
import {
  ChevronDown,
  ChevronLeft,
  ChevronRight,
  Clock3,
  AlertCircle,
  BadgeDollarSign,
  DollarSign,
  Eye,
  EyeOff,
  LayoutGrid,
  ListChecks,
  Inbox,
  FileX2,
  LogOut,
  Plus,
  RefreshCw,
  Search,
  SlidersHorizontal,
  X,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
  DropdownMenu,
  DropdownMenuTrigger,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
} from "@/components/ui/dropdown-menu";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { ProjectCard } from "@/components/board/ProjectCard";
import { ProjectDialog } from "@/components/board/ProjectDialog";
import { ProjectTimeDialog } from "@/components/board/ProjectTimeDialog";
import { TeamHoursDialog } from "@/components/board/TeamHoursDialog";
import { BriefReviewCard } from "@/components/board/BriefReviewCard";
import { SearchableSelect } from "@/components/board/SearchableSelect";
import {
  useProjectPricingSummary,
  useProjects,
  type Project,
  type ProjectTab,
} from "@/lib/store";
import { useBriefInbox, useBriefUnreadCount, type BriefReviewStatus } from "@/lib/briefInbox";
import { usePricingSummaryVisibility } from "@/lib/pricingSummaryVisibility";
import { useAppLists } from "@/lib/appLists";
import { useAuth } from "@/context/AuthContext";
import { dedupeOptions } from "@/lib/optionUtils";
import { expandCountryOptions, expandMultiValueOptions } from "@/lib/filterNormalization";
import { GLMLogo } from "@/components/GLMLogo";
import { TariffManagerDialog } from "@/components/tariff/TariffManagerDialog";
import { ListManagerDialog } from "@/components/lists/ListManagerDialog";

/** Extract up-to-2-letter initials from a display name or email */
const PROJECTS_PER_PAGE = 24;

type BoardView = "nuevos" | ProjectTab | "no_aprobados";

type AdvancedFilters = {
  country: string;
  brand: string;
  client: string;
  cm: string;
};

const EMPTY_ADVANCED_FILTERS: AdvancedFilters = {
  country: "",
  brand: "",
  client: "",
  cm: "",
};

const DEFAULT_PAGE_BY_FILTER: Record<BoardView, number> = {
  nuevos: 1,
  todos: 1,
  abiertos: 1,
  cerrados: 1,
  no_aprobados: 1,
};

const BOARD_UI_STATE_KEY = "tablero-cdc:ui-state:v1";

type PersistedBoardUiState = {
  query: string;
  filter: BoardView;
  advancedFilters: AdvancedFilters;
  pageByFilter: Record<BoardView, number>;
  tariffManagerOpen: boolean;
  listManagerOpen: boolean;
  teamHoursOpen: boolean;
  scrollY: number;
};

function loadBoardUiState(): PersistedBoardUiState {
  const fallback: PersistedBoardUiState = {
    query: "",
    filter: "todos",
    advancedFilters: EMPTY_ADVANCED_FILTERS,
    pageByFilter: DEFAULT_PAGE_BY_FILTER,
    tariffManagerOpen: false,
    listManagerOpen: false,
    teamHoursOpen: false,
    scrollY: 0,
  };

  if (typeof window === "undefined") return fallback;

  try {
    const raw = window.localStorage.getItem(BOARD_UI_STATE_KEY);
    if (!raw) return fallback;
    const parsed = JSON.parse(raw) as Partial<PersistedBoardUiState>;
    const validFilters: BoardView[] = ["nuevos", "todos", "abiertos", "cerrados", "no_aprobados"];
    const nextFilter = validFilters.includes(parsed.filter as BoardView)
      ? (parsed.filter as BoardView)
      : fallback.filter;

    return {
      // Búsquedas y filtros avanzados son temporales: no se restauran tras una recarga
      // o descarte de pestaña para evitar que el tablero parezca incompleto al volver.
      query: "",
      filter: nextFilter,
      advancedFilters: EMPTY_ADVANCED_FILTERS,
      pageByFilter: Object.fromEntries(
        Object.entries({ ...DEFAULT_PAGE_BY_FILTER, ...(parsed.pageByFilter || {}) }).map(([key, value]) => [
          key,
          Math.max(1, Math.floor(Number(value) || 1)),
        ]),
      ) as Record<BoardView, number>,
      tariffManagerOpen: parsed.tariffManagerOpen === true,
      listManagerOpen: parsed.listManagerOpen === true,
      teamHoursOpen: parsed.teamHoursOpen === true,
      scrollY: Number.isFinite(Number(parsed.scrollY)) ? Math.max(0, Number(parsed.scrollY)) : 0,
    };
  } catch (error) {
    console.warn("No se pudo restaurar la vista anterior del Tablero CDC:", error);
    return fallback;
  }
}

function initials(name: string | null | undefined, email: string | null | undefined): string {
  if (name) {
    const parts = name.trim().split(/\s+/);
    if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase();
    return name.slice(0, 2).toUpperCase();
  }
  if (email) return email.slice(0, 2).toUpperCase();
  return "?";
}

export default function BoardPage() {
  const [initialUiState] = useState(loadBoardUiState);
  const hasMountedFilterReset = useRef(false);
  const hasRestoredScroll = useRef(initialUiState.scrollY <= 0);
  const [open, setOpen] = useState(false);
  const [editing, setEditing] = useState<Project | null>(null);
  const [query, setQuery] = useState(initialUiState.query);
  const [filter, setFilter] = useState<BoardView>(initialUiState.filter);
  const [advancedFilters, setAdvancedFilters] = useState<AdvancedFilters>(initialUiState.advancedFilters);
  const [pageByFilter, setPageByFilter] = useState<Record<BoardView, number>>(initialUiState.pageByFilter);
  const [deletingProjectId, setDeletingProjectId] = useState<string | null>(null);
  const [tariffManagerOpen, setTariffManagerOpen] = useState(initialUiState.tariffManagerOpen);
  const [listManagerOpen, setListManagerOpen] = useState(initialUiState.listManagerOpen);
  const [teamHoursOpen, setTeamHoursOpen] = useState(initialUiState.teamHoursOpen);
  const [timeProject, setTimeProject] = useState<Project | null>(null);
  const [reviewingBriefId, setReviewingBriefId] = useState<string | null>(null);

  const isBriefReviewView = filter === "nuevos" || filter === "no_aprobados";
  const briefStatus: BriefReviewStatus = filter === "no_aprobados" ? "rejected" : "new";
  const projectFilter: ProjectTab = isBriefReviewView ? "todos" : filter;
  const currentPage = pageByFilter[filter];
  const { lists } = useAppLists();
  const { projects, totalProjects, filterOptions, loading, error, refresh, remove } = useProjects({
    tab: projectFilter,
    search: isBriefReviewView ? "" : query,
    page: isBriefReviewView ? pageByFilter[projectFilter] : currentPage,
    pageSize: PROJECTS_PER_PAGE,
    country: isBriefReviewView ? "" : advancedFilters.country,
    brand: isBriefReviewView ? "" : advancedFilters.brand,
    client: isBriefReviewView ? "" : advancedFilters.client,
    cm: isBriefReviewView ? "" : advancedFilters.cm,
  });
  const briefInbox = useBriefInbox({
    status: briefStatus,
    search: query,
    page: currentPage,
    pageSize: PROJECTS_PER_PAGE,
    enabled: isBriefReviewView,
  });
  const {
    user,
    isGerardo,
    canManageInternalPricing,
    canControlPricingSummary,
    canManageTariffCatalog,
    canViewTeamHours,
    canCreateProjects,
    logout,
  } = useAuth();
  const briefUnread = useBriefUnreadCount(Boolean(user));

  useEffect(() => {
    if (!canViewTeamHours && teamHoursOpen) setTeamHoursOpen(false);
  }, [canViewTeamHours, teamHoursOpen]);
  const pricingSummaryParams = {
    tab: projectFilter,
    search: isBriefReviewView ? "" : query,
    page: 1,
    pageSize: PROJECTS_PER_PAGE,
    country: isBriefReviewView ? "" : advancedFilters.country,
    brand: isBriefReviewView ? "" : advancedFilters.brand,
    client: isBriefReviewView ? "" : advancedFilters.client,
    cm: isBriefReviewView ? "" : advancedFilters.cm,
  } as const;
  const {
    isPublic: isPricingSummaryPublic,
    loading: pricingSummaryVisibilityLoading,
    saving: pricingSummaryVisibilitySaving,
    error: pricingSummaryVisibilityError,
    setPublicVisibility: setPricingSummaryPublicVisibility,
  } = usePricingSummaryVisibility(Boolean(user));
  const canViewPricingSummary =
    !isBriefReviewView && (canControlPricingSummary || isPricingSummaryPublic);
  const {
    summary: pricingSummary,
    loading: pricingSummaryLoading,
    error: pricingSummaryError,
  } = useProjectPricingSummary(pricingSummaryParams, canViewPricingSummary);

  const cmListOptions = Object.values(lists.buCm);
  const countryFilterOptions = dedupeOptions([
    ...lists.bus,
    ...expandCountryOptions(filterOptions.countries, lists.bus),
    advancedFilters.country,
  ]);
  const brandFilterOptions = dedupeOptions([
    ...lists.marcas,
    ...expandMultiValueOptions(filterOptions.brands, lists.marcas),
    advancedFilters.brand,
  ]);
  const clientFilterOptions = dedupeOptions([
    ...lists.clientes,
    ...expandMultiValueOptions(filterOptions.clients, lists.clientes),
    advancedFilters.client,
  ]);
  const cmFilterOptions = dedupeOptions([
    ...cmListOptions,
    ...expandMultiValueOptions(filterOptions.cms, cmListOptions),
    advancedFilters.cm,
  ]);
  const activeAdvancedFilterCount = Object.values(advancedFilters).filter(Boolean).length;

  const currentTotalItems = isBriefReviewView ? briefInbox.totalItems : totalProjects;
  const totalPages = Math.max(1, Math.ceil(currentTotalItems / PROJECTS_PER_PAGE));
  const safePage = Math.min(currentPage, totalPages);
  const pageStart = (safePage - 1) * PROJECTS_PER_PAGE;
  const visibleStart = currentTotalItems === 0 ? 0 : pageStart + 1;
  const visibleEnd = Math.min(pageStart + PROJECTS_PER_PAGE, currentTotalItems);

  useEffect(() => {
    if (!hasMountedFilterReset.current) {
      hasMountedFilterReset.current = true;
      return;
    }
    setPageByFilter((prev) => ({ ...prev, [filter]: 1 }));
  }, [
    query,
    advancedFilters.country,
    advancedFilters.brand,
    advancedFilters.client,
    advancedFilters.cm,
  ]);

  useEffect(() => {
    const saveUiState = () => {
      try {
        const nextState: PersistedBoardUiState = {
          // Conservamos navegación/posición, pero no búsquedas ni filtros transitorios.
          query: "",
          filter,
          advancedFilters: EMPTY_ADVANCED_FILTERS,
          pageByFilter,
          tariffManagerOpen,
          listManagerOpen,
          teamHoursOpen,
          scrollY: hasRestoredScroll.current ? window.scrollY : initialUiState.scrollY,
        };
        window.localStorage.setItem(BOARD_UI_STATE_KEY, JSON.stringify(nextState));
      } catch (error) {
        console.warn("No se pudo guardar la vista del Tablero CDC:", error);
      }
    };

    saveUiState();
    const handlePageHide = () => saveUiState();
    const handleVisibilityChange = () => {
      if (document.visibilityState === "hidden") saveUiState();
    };

    window.addEventListener("pagehide", handlePageHide);
    document.addEventListener("visibilitychange", handleVisibilityChange);

    return () => {
      window.removeEventListener("pagehide", handlePageHide);
      document.removeEventListener("visibilitychange", handleVisibilityChange);
    };
  }, [query, filter, advancedFilters, pageByFilter, tariffManagerOpen, listManagerOpen, teamHoursOpen, initialUiState.scrollY]);

  useEffect(() => {
    const savedScrollY = initialUiState.scrollY;
    const currentViewLoading = isBriefReviewView ? briefInbox.loading : loading;
    if (savedScrollY <= 0 || currentViewLoading || hasRestoredScroll.current) return;

    const timer = window.setTimeout(() => {
      window.scrollTo({ top: savedScrollY, behavior: "auto" });
      hasRestoredScroll.current = true;
    }, 120);

    return () => window.clearTimeout(timer);
  }, [initialUiState.scrollY, isBriefReviewView, briefInbox.loading, loading]);

  useEffect(() => {
    if (currentPage > totalPages) {
      setPageByFilter((prev) => ({ ...prev, [filter]: totalPages }));
    }
  }, [currentPage, filter, totalPages]);

  // Entering "Nuevos" clears only this user's pending notification. If a new
  // brief arrives while this view is open, Realtime increments unreadCount and
  // this effect immediately marks that currently visible queue as seen again.
  // Other teammates keep their own independent unread state.
  useEffect(() => {
    if (filter !== "nuevos" || !user || briefUnread.unreadCount <= 0) return;

    void briefUnread.markAllSeen().catch((markError) => {
      console.error("Error marcando briefs como vistos:", markError);
    });
  }, [filter, user?.id, briefUnread.unreadCount, briefUnread.markAllSeen]);

  const goToPage = (page: number) => {
    const nextPage = Math.min(Math.max(page, 1), totalPages);

    if (nextPage === currentPage) return;

    setPageByFilter((prev) => ({ ...prev, [filter]: nextPage }));
    window.scrollTo({ top: 0, behavior: "smooth" });
  };

  const setAdvancedFilter = (key: keyof AdvancedFilters, value: string) => {
    setAdvancedFilters((current) => ({ ...current, [key]: value }));
  };

  const clearAdvancedFilters = () => {
    setAdvancedFilters(EMPTY_ADVANCED_FILTERS);
  };

  const openNew = () => {
    if (!canCreateProjects) return;
    setEditing(null);
    setOpen(true);
  };
  const openEdit = (p: Project) => {
    setEditing(p);
    setOpen(true);
  };

  const deleteProject = async (project: Project) => {
    const confirmed = window.confirm(
      `¿Seguro que deseas eliminar el proyecto "${project.nombre || "Sin título"}"?\n\nEsta acción eliminará el proyecto del tablero y del Google Sheet.`,
    );

    if (!confirmed) return;

    setDeletingProjectId(project.id);

    try {
      await remove(project.id);

      if (editing?.id === project.id) {
        setOpen(false);
        setEditing(null);
      }
    } catch (err) {
      console.error("Error eliminando proyecto:", err);
      const message =
        err instanceof Error
          ? err.message
          : "No se pudo eliminar el proyecto. Revisa n8n, Supabase o permisos.";
      window.alert(message);
    } finally {
      setDeletingProjectId(null);
    }
  };

  const approveBrief = async (briefId: string, title: string, fromRejected = false) => {
    const confirmed = window.confirm(
      fromRejected
        ? `¿Aprobar el brief rechazado "${title || "Sin título"}"?\n\nSe recuperará de Rechazados, se creará como proyecto Activo y aparecerá en Todos y Activos.`
        : `¿Aprobar el brief "${title || "Sin título"}"?\n\nSe creará como proyecto Activo y aparecerá en Todos y Activos.`,
    );

    if (!confirmed || reviewingBriefId) return;

    setReviewingBriefId(briefId);

    try {
      const result = await briefInbox.approve(briefId);
      await refresh();

      if (result.sheetSyncStatus === "synced") {
        window.alert("Brief aprobado. El proyecto quedó Activo y sincronizado con Google Sheet.");
      } else {
        window.alert(result.sheetSyncMessage);
      }
    } catch (reviewError) {
      console.error("Error aprobando brief:", reviewError);
      window.alert(
        reviewError instanceof Error
          ? reviewError.message
          : "No se pudo aprobar el brief. Revisa Supabase e intenta de nuevo.",
      );
    } finally {
      setReviewingBriefId(null);
    }
  };

  const rejectBrief = async (briefId: string, title: string) => {
    const confirmed = window.confirm(
      `¿Mover el brief "${title || "Sin título"}" a Rechazados?\n\nNo se creará ningún proyecto en el tablero general.`,
    );

    if (!confirmed || reviewingBriefId) return;

    setReviewingBriefId(briefId);

    try {
      await briefInbox.reject(briefId);
    } catch (reviewError) {
      console.error("Error marcando brief como rechazado:", reviewError);
      window.alert(
        reviewError instanceof Error
          ? reviewError.message
          : "No se pudo mover el brief a Rechazados. Revisa Supabase e intenta de nuevo.",
      );
    } finally {
      setReviewingBriefId(null);
    }
  };

  const displayName = user?.displayName ?? user?.email ?? "Usuario";
  const userRole = isGerardo ? "Jefe CDC" : "Usuario CDC";
  const userInitials = initials(user?.displayName, user?.email);

  return (
    <div className="min-h-screen bg-background">
      {/* Top bar */}
      <header className="sticky top-0 z-30 bg-background/85 backdrop-blur-md border-b border-border">
        <div className="max-w-[1400px] mx-auto px-6 py-3.5 flex items-center gap-4">
          {/* Brand */}
          <div className="flex items-center gap-4">
            <GLMLogo size="sm" />
            <div className="h-7 w-px bg-border" />
            <h1 className="text-[15px] font-semibold tracking-tight text-[#4F758B]">CDC Project Management</h1>
          </div>

          {/* Search */}
          <div className="flex-1 max-w-md ml-4 relative hidden md:block">
            <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
            <Input
              value={query}
              onChange={(e) => setQuery(e.target.value)}
              placeholder={isBriefReviewView ? "Buscar brief, cliente, marca…" : "Buscar proyecto, cliente, marca…"}
              className="pl-9 h-9 bg-muted/40 border-transparent focus-visible:bg-card focus-visible:border-border"
            />
          </div>

          <div className="flex-1 md:flex-none" />

          {/* User menu — real authenticated user */}
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button variant="ghost" size="sm" className="gap-2 h-9 px-2.5">
                <Avatar className="w-7 h-7">
                  {user?.photoURL && (
                    <AvatarImage
                      src={user.photoURL}
                      alt={displayName}
                      referrerPolicy="no-referrer"
                    />
                  )}
                  <AvatarFallback
                    className={
                      isGerardo
                        ? "bg-primary text-primary-foreground text-xs"
                        : "bg-accent text-accent-foreground text-xs"
                    }
                  >
                    {userInitials}
                  </AvatarFallback>
                </Avatar>
                <div className="text-left leading-tight hidden sm:block">
                  <div className="text-xs font-medium">{displayName}</div>
                  <div className="text-[10px] text-muted-foreground">{userRole}</div>
                </div>
                <ChevronDown className="w-3.5 h-3.5 text-muted-foreground" />
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="end" className="w-52">
              <div className="px-3 py-2">
                <p className="text-xs font-medium truncate">{displayName}</p>
                <p className="text-[10px] text-muted-foreground truncate">{user?.email}</p>
              </div>
              <DropdownMenuSeparator />
              <DropdownMenuItem
                onClick={logout}
                className="gap-2 text-destructive focus:text-destructive focus:bg-destructive/10 cursor-pointer"
              >
                <LogOut className="w-3.5 h-3.5" />
                Cerrar sesión
              </DropdownMenuItem>
            </DropdownMenuContent>
          </DropdownMenu>

          {/* Team time overview — controlled by Supabase permission */}
          {canViewTeamHours && (
            <Button
              type="button"
              variant="outline"
              onClick={() => setTeamHoursOpen(true)}
              className="gap-1.5 h-9 rounded-full px-4 shadow-sm"
            >
              <Clock3 className="w-4 h-4" /> Horas del equipo
            </Button>
          )}

          {/* Tariff administration — controlled by Supabase permission */}
          {canManageTariffCatalog && (
            <Button
              type="button"
              variant="outline"
              onClick={() => setTariffManagerOpen(true)}
              className="gap-1.5 h-9 rounded-full px-4 shadow-sm"
            >
              <BadgeDollarSign className="w-4 h-4" /> Tarifario
            </Button>
          )}

          {/* App lists administration — same trusted admin permission as Tarifario */}
          {canManageTariffCatalog && (
            <Button
              type="button"
              variant="outline"
              onClick={() => setListManagerOpen(true)}
              className="gap-1.5 h-9 rounded-full px-4 shadow-sm"
            >
              <ListChecks className="w-4 h-4" /> Listas
            </Button>
          )}

          {/* New project button — controlled by Supabase permission */}
          {canCreateProjects && (
            <Button onClick={openNew} className="gap-1.5 h-9 rounded-full px-4 shadow-sm">
              <Plus className="w-4 h-4" /> Nuevo
            </Button>
          )}
        </div>
      </header>

      {/* Filters */}
      <div className="max-w-[1400px] mx-auto px-6 pt-6 pb-3 space-y-3">
        <div className="flex items-center justify-between gap-4 flex-wrap">
          <div>
            <h2 className="text-2xl font-semibold tracking-tight">
              {filter === "nuevos"
                ? "Briefs por revisar"
                : filter === "no_aprobados"
                  ? "Briefs rechazados"
                  : "Proyectos"}
            </h2>
            {filter === "nuevos" && (
              <p className="mt-1 text-xs text-muted-foreground">
                Los briefs de CDC Brief llegan aquí antes de convertirse en proyectos Activos.
              </p>
            )}
            {filter === "no_aprobados" && (
              <p className="mt-1 text-xs text-muted-foreground">
                Briefs revisados que no se incorporaron al tablero general.
              </p>
            )}
          </div>

          <div className="flex items-center gap-2">
            <div className="inline-flex flex-wrap bg-muted/60 rounded-full p-1 text-xs">
              {(
                [
                  ["todos", "Todos"],
                  ["abiertos", "Activos"],
                  ["cerrados", "Cerrados"],
                  ["nuevos", "Nuevos"],
                  ["no_aprobados", "Rechazados"],
                ] as const
              ).map(([k, l]) => (
                <button
                  key={k}
                  onClick={() => setFilter(k)}
                  className={`inline-flex items-center gap-1.5 px-3.5 py-1.5 rounded-full transition-colors font-medium ${
                    filter === k
                      ? "bg-card text-foreground shadow-sm"
                      : "text-muted-foreground hover:text-foreground"
                  }`}
                >
                  <span>{l}</span>
                  {k === "nuevos" && briefUnread.unreadCount > 0 && (
                    <span
                      className="inline-flex min-w-[18px] h-[18px] items-center justify-center rounded-full bg-red-500 px-1 text-[10px] font-bold leading-none text-white shadow-sm"
                      aria-label={`${briefUnread.unreadCount} briefs nuevos sin revisar`}
                    >
                      {briefUnread.unreadCount > 99 ? "99+" : briefUnread.unreadCount}
                    </span>
                  )}
                </button>
              ))}
            </div>
          </div>
        </div>

        <div className="relative md:hidden">
          <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
          <Input
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            placeholder={isBriefReviewView ? "Buscar brief, cliente, marca…" : "Buscar proyecto, cliente, marca…"}
            className="pl-9 h-9 bg-muted/40 border-transparent focus-visible:bg-card focus-visible:border-border"
          />
        </div>

        {!isBriefReviewView && (
          <AdvancedProjectFilters
            filters={advancedFilters}
            activeCount={activeAdvancedFilterCount}
            countryOptions={countryFilterOptions}
            brandOptions={brandFilterOptions}
            clientOptions={clientFilterOptions}
            cmOptions={cmFilterOptions}
            onFilterChange={setAdvancedFilter}
            onClear={clearAdvancedFilters}
          />
        )}

        {canViewPricingSummary && (
          <PricingSummaryCard
            totalAmount={pricingSummary.totalAmount}
            projectCount={pricingSummary.projectCount}
            loading={pricingSummaryLoading || pricingSummaryVisibilityLoading}
            error={pricingSummaryError || pricingSummaryVisibilityError}
            hasFilters={
              filter !== "todos" || query.trim().length > 0 || activeAdvancedFilterCount > 0
            }
            canControlVisibility={canControlPricingSummary}
            isPublic={isPricingSummaryPublic}
            visibilitySaving={pricingSummaryVisibilitySaving}
            onToggleVisibility={() =>
              setPricingSummaryPublicVisibility(!isPricingSummaryPublic).catch(() => undefined)
            }
          />
        )}
      </div>

      {/* Grid */}
      <main className="max-w-[1400px] mx-auto px-6 pb-16">
        {(isBriefReviewView ? briefInbox.error : error) && (
          <div className="mb-4 flex flex-col gap-3 rounded-2xl border border-destructive/30 bg-destructive/5 px-4 py-3 text-sm text-destructive sm:flex-row sm:items-center sm:justify-between">
            <span className="flex items-start gap-2">
              <AlertCircle className="mt-0.5 h-4 w-4 flex-shrink-0" />
              <span>
                <span className="font-medium">
                  {isBriefReviewView
                    ? "No se pudieron cargar los briefs."
                    : "No se pudieron cargar los proyectos."}
                </span>{" "}
                {isBriefReviewView ? briefInbox.error : error}
              </span>
            </span>
            <Button
              variant="outline"
              size="sm"
              onClick={() => void (isBriefReviewView ? briefInbox.refresh() : refresh())}
              className="gap-1.5"
            >
              <RefreshCw className="h-3.5 w-3.5" /> Reintentar
            </Button>
          </div>
        )}

        {isBriefReviewView ? (
          briefInbox.loading && briefInbox.items.length === 0 ? (
            <LoadingState />
          ) : briefInbox.items.length === 0 ? (
            <BriefEmptyState mode={briefStatus} query={query} />
          ) : (
            <div className="grid grid-cols-1 gap-4 lg:grid-cols-2 xl:grid-cols-3">
              {briefInbox.items.map((item) => (
                <BriefReviewCard
                  key={item.id}
                  item={item}
                  mode={briefStatus}
                  busy={reviewingBriefId === item.id}
                  onApprove={() => void approveBrief(item.id, item.title, briefStatus === "rejected")}
                  onReject={() => void rejectBrief(item.id, item.title)}
                />
              ))}
            </div>
          )
        ) : loading && projects.length === 0 ? (
          <LoadingState />
        ) : projects.length === 0 ? (
          <EmptyState
            onNew={openNew}
            hasProjects={
              totalProjects > 0 ||
              projectFilter !== "todos" ||
              query.trim().length > 0 ||
              activeAdvancedFilterCount > 0
            }
            filter={projectFilter}
            query={query}
            activeAdvancedFilterCount={activeAdvancedFilterCount}
          />
        ) : (
          <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
            {projects.map((p) => (
              <ProjectCard
                key={p.id}
                project={p}
                onClick={() => openEdit(p)}
                onTimeClick={() => setTimeProject(p)}
                showInternalAmount={canManageInternalPricing}
              />
            ))}
          </div>
        )}

        {currentTotalItems > PROJECTS_PER_PAGE && (
          <PaginationControls
            currentPage={safePage}
            totalPages={totalPages}
            visibleStart={visibleStart}
            visibleEnd={visibleEnd}
            totalItems={currentTotalItems}
            itemLabel={isBriefReviewView ? "briefs" : "proyectos"}
            onPageChange={goToPage}
          />
        )}
      </main>

      <ProjectDialog
        open={open}
        onOpenChange={setOpen}
        project={editing}
        onDelete={deleteProject}
        deleting={!!editing && deletingProjectId === editing.id}
      />

      <ProjectTimeDialog
        open={!!timeProject}
        onOpenChange={(nextOpen) => {
          if (!nextOpen) setTimeProject(null);
        }}
        project={timeProject}
      />

      {canViewTeamHours && (
        <TeamHoursDialog open={teamHoursOpen} onOpenChange={setTeamHoursOpen} />
      )}

      {canManageTariffCatalog && (
        <>
          <TariffManagerDialog
            open={tariffManagerOpen}
            onOpenChange={setTariffManagerOpen}
          />
          <ListManagerDialog
            open={listManagerOpen}
            onOpenChange={setListManagerOpen}
          />
        </>
      )}
    </div>
  );
}

function formatCurrency(value: number) {
  return new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "USD",
    maximumFractionDigits: 2,
  }).format(value || 0);
}

function PricingSummaryCard({
  totalAmount,
  projectCount,
  loading,
  error,
  hasFilters,
  canControlVisibility,
  isPublic,
  visibilitySaving,
  onToggleVisibility,
}: {
  totalAmount: number;
  projectCount: number;
  loading: boolean;
  error: string | null;
  hasFilters: boolean;
  canControlVisibility: boolean;
  isPublic: boolean;
  visibilitySaving: boolean;
  onToggleVisibility: () => void;
}) {
  return (
    <div className="rounded-2xl border border-primary/15 bg-primary/5 px-4 py-3 shadow-sm">
      <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
        <div className="flex items-start gap-3">
          <span className="mt-0.5 flex h-9 w-9 items-center justify-center rounded-xl bg-primary/10 text-primary">
            <DollarSign className="h-4 w-4" />
          </span>
          <div>
            <div className="flex flex-wrap items-center gap-2">
              <p className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
                {hasFilters ? "Total tarifado filtrado" : "Total tarifado global"}
              </p>
              <span
                className={`rounded-full border px-2 py-0.5 text-[10px] font-medium ${
                  isPublic
                    ? "border-emerald-200 bg-emerald-50 text-emerald-700"
                    : "border-primary/20 bg-card text-primary"
                }`}
              >
                {isPublic ? "Visible para todos" : "Privado"}
              </span>
            </div>
            <p className="mt-0.5 text-2xl font-semibold tracking-tight text-foreground">
              {loading ? "Calculando…" : formatCurrency(totalAmount)}
            </p>
            <p className="text-xs text-muted-foreground">
              {error
                ? `No se pudo calcular el total: ${error}`
                : `${projectCount} proyecto(s) incluidos según los filtros actuales.`}
            </p>
          </div>
        </div>

        <div className="flex flex-col gap-2 sm:flex-row sm:items-center lg:justify-end">
          <div className="rounded-full border border-primary/20 bg-card px-3 py-1 text-xs font-medium text-primary">
            {hasFilters ? "Según filtros activos" : "Sin filtros aplicados"}
          </div>

          {canControlVisibility && (
            <Button
              type="button"
              variant={isPublic ? "secondary" : "outline"}
              size="sm"
              className="gap-1.5 rounded-full"
              disabled={visibilitySaving}
              onClick={onToggleVisibility}
              title={
                isPublic
                  ? "Ocultar este total para los demás usuarios"
                  : "Mostrar este total temporalmente a todos los usuarios"
              }
            >
              {isPublic ? <EyeOff className="h-3.5 w-3.5" /> : <Eye className="h-3.5 w-3.5" />}
              {visibilitySaving
                ? "Actualizando…"
                : isPublic
                  ? "Ocultar a todos"
                  : "Mostrar a todos"}
            </Button>
          )}
        </div>
      </div>
    </div>
  );
}

function AdvancedProjectFilters({
  filters,
  activeCount,
  countryOptions,
  brandOptions,
  clientOptions,
  cmOptions,
  onFilterChange,
  onClear,
}: {
  filters: AdvancedFilters;
  activeCount: number;
  countryOptions: string[];
  brandOptions: string[];
  clientOptions: string[];
  cmOptions: string[];
  onFilterChange: (key: keyof AdvancedFilters, value: string) => void;
  onClear: () => void;
}) {
  return (
    <div className="rounded-2xl border border-border bg-card/70 px-3.5 py-3 shadow-sm">
      <div className="flex flex-col gap-3 lg:flex-row lg:items-center">
        <div className="flex items-center justify-between gap-3 lg:w-auto lg:min-w-[120px] lg:justify-start">
          <div className="flex items-center gap-2 text-sm font-medium">
            <span className="flex h-8 w-8 items-center justify-center rounded-full bg-primary/10 text-primary">
              <SlidersHorizontal className="h-4 w-4" />
            </span>
            <span>Filtros</span>
            {activeCount > 0 && (
              <span className="rounded-full bg-primary/10 px-2 py-0.5 text-[11px] font-semibold text-primary">
                {activeCount}
              </span>
            )}
          </div>

          {activeCount > 0 && (
            <Button
              type="button"
              variant="ghost"
              size="sm"
              onClick={onClear}
              className="h-8 rounded-full px-2.5 text-xs text-muted-foreground hover:text-foreground lg:hidden"
            >
              <X className="mr-1 h-3.5 w-3.5" />
              Limpiar
            </Button>
          )}
        </div>

        <div className="grid flex-1 grid-cols-1 gap-2 sm:grid-cols-2 xl:grid-cols-4">
          <SearchableSelect
            value={filters.country}
            options={countryOptions}
            onValueChange={(value) => onFilterChange("country", value)}
            placeholder="País: Todos"
            searchPlaceholder="Buscar país…"
            emptyText="No se encontró ese país."
            clearLabel="Todos"
          />
          <SearchableSelect
            value={filters.brand}
            options={brandOptions}
            onValueChange={(value) => onFilterChange("brand", value)}
            placeholder="Marca: Todas"
            searchPlaceholder="Buscar marca…"
            emptyText="No se encontró esa marca."
            clearLabel="Todas"
          />
          <SearchableSelect
            value={filters.client}
            options={clientOptions}
            onValueChange={(value) => onFilterChange("client", value)}
            placeholder="Cliente: Todos"
            searchPlaceholder="Buscar cliente…"
            emptyText="No se encontró ese cliente."
            clearLabel="Todos"
          />
          <SearchableSelect
            value={filters.cm}
            options={cmOptions}
            onValueChange={(value) => onFilterChange("cm", value)}
            placeholder="CM: Todos"
            searchPlaceholder="Buscar CM…"
            emptyText="No se encontró ese CM."
            clearLabel="Todos"
          />
        </div>

        <Button
          type="button"
          variant="ghost"
          size="sm"
          onClick={onClear}
          disabled={activeCount === 0}
          className="hidden h-9 rounded-full px-3 text-xs text-muted-foreground hover:text-foreground lg:inline-flex"
        >
          <X className="mr-1 h-3.5 w-3.5" />
          Limpiar
        </Button>
      </div>
    </div>
  );
}

function PaginationControls({
  currentPage,
  totalPages,
  visibleStart,
  visibleEnd,
  totalItems,
  itemLabel = "proyectos",
  onPageChange,
}: {
  currentPage: number;
  totalPages: number;
  visibleStart: number;
  visibleEnd: number;
  totalItems: number;
  itemLabel?: string;
  onPageChange: (page: number) => void;
}) {
  const pages = getVisiblePages(currentPage, totalPages);

  return (
    <div className="mt-6 flex flex-col sm:flex-row items-center justify-between gap-3 rounded-2xl border border-border bg-card/70 px-4 py-3">
      <p className="text-xs text-muted-foreground">
        <span className="font-medium text-foreground">
          {visibleStart}-{visibleEnd}
        </span>{" "}
        de <span className="font-medium text-foreground">{totalItems}</span> {itemLabel}
      </p>

      <div className="flex items-center gap-1.5">
        <Button
          type="button"
          variant="ghost"
          size="sm"
          className="h-8 gap-1 rounded-full px-2.5"
          onClick={() => onPageChange(currentPage - 1)}
          disabled={currentPage === 1}
        >
          <ChevronLeft className="h-4 w-4" />
          <span className="hidden sm:inline">Anterior</span>
        </Button>

        <div className="flex items-center gap-1">
          {pages.map((page, index) =>
            page === "ellipsis" ? (
              <span
                key={`ellipsis-${index}`}
                className="flex h-8 w-8 items-center justify-center text-xs text-muted-foreground"
              >
                …
              </span>
            ) : (
              <Button
                key={page}
                type="button"
                variant={page === currentPage ? "default" : "ghost"}
                size="sm"
                className="h-8 w-8 rounded-full p-0 text-xs"
                onClick={() => onPageChange(page)}
                aria-current={page === currentPage ? "page" : undefined}
              >
                {page}
              </Button>
            ),
          )}
        </div>

        <Button
          type="button"
          variant="ghost"
          size="sm"
          className="h-8 gap-1 rounded-full px-2.5"
          onClick={() => onPageChange(currentPage + 1)}
          disabled={currentPage === totalPages}
        >
          <span className="hidden sm:inline">Siguiente</span>
          <ChevronRight className="h-4 w-4" />
        </Button>
      </div>
    </div>
  );
}

function getVisiblePages(currentPage: number, totalPages: number): Array<number | "ellipsis"> {
  if (totalPages <= 7) return Array.from({ length: totalPages }, (_, index) => index + 1);

  const pages = new Set<number>([1, totalPages, currentPage]);

  if (currentPage > 1) pages.add(currentPage - 1);
  if (currentPage < totalPages) pages.add(currentPage + 1);
  if (currentPage <= 3) {
    pages.add(2);
    pages.add(3);
    pages.add(4);
  }
  if (currentPage >= totalPages - 2) {
    pages.add(totalPages - 3);
    pages.add(totalPages - 2);
    pages.add(totalPages - 1);
  }

  const sortedPages = Array.from(pages)
    .filter((page) => page >= 1 && page <= totalPages)
    .sort((a, b) => a - b);

  return sortedPages.reduce<Array<number | "ellipsis">>((acc, page) => {
    const previous = acc[acc.length - 1];
    if (typeof previous === "number" && page - previous > 1) acc.push("ellipsis");
    acc.push(page);
    return acc;
  }, []);
}

function LoadingState() {
  return (
    <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
      {Array.from({ length: 8 }).map((_, index) => (
        <div
          key={index}
          className="min-h-[230px] overflow-hidden rounded-2xl border border-border bg-card"
        >
          <div className="h-14 bg-muted animate-pulse" />
          <div className="space-y-3 p-4">
            <div className="h-3 w-3/4 rounded-full bg-muted animate-pulse" />
            <div className="h-3 w-2/3 rounded-full bg-muted animate-pulse" />
            <div className="h-3 w-1/2 rounded-full bg-muted animate-pulse" />
            <div className="mt-6 h-8 rounded-full bg-muted animate-pulse" />
          </div>
        </div>
      ))}
    </div>
  );
}

function BriefEmptyState({ mode, query }: { mode: BriefReviewStatus; query: string }) {
  const hasSearch = query.trim().length > 0;
  const isRejected = mode === "rejected";

  return (
    <div className="rounded-2xl border border-dashed border-border bg-card/40 py-24 text-center">
      <div
        className={`mx-auto mb-4 flex h-14 w-14 items-center justify-center rounded-2xl ${
          isRejected ? "bg-red-50 text-red-600" : "bg-amber-50 text-amber-700"
        }`}
      >
        {isRejected ? <FileX2 className="h-6 w-6" /> : <Inbox className="h-6 w-6" />}
      </div>
      <h3 className="text-lg font-semibold">
        {hasSearch
          ? "No hay briefs que coincidan con la búsqueda"
          : isRejected
            ? "No hay briefs rechazados"
            : "No hay briefs pendientes"}
      </h3>
      <p className="mx-auto mt-1 max-w-md text-sm text-muted-foreground">
        {hasSearch
          ? "Prueba con otro nombre, cliente, marca, país o solicitante."
          : isRejected
            ? "Los briefs que el equipo decida no convertir en proyecto aparecerán aquí."
            : "Cuando CDC Brief genere un nuevo brief, aparecerá aquí automáticamente para revisión."}
      </p>
    </div>
  );
}

function EmptyState({
  onNew,
  hasProjects,
  filter,
  query,
  activeAdvancedFilterCount,
}: {
  onNew: () => void;
  hasProjects: boolean;
  filter: ProjectTab;
  query: string;
  activeAdvancedFilterCount: number;
}) {
  const hasSearch = query.trim().length > 0;
  const hasAdvancedFilters = activeAdvancedFilterCount > 0;

  let title = "Tu tablero está vacío";
  let message = "Crea tu primer proyecto para que el equipo pueda darle seguimiento.";

  if (hasProjects && hasSearch && hasAdvancedFilters) {
    title = "Nada coincide con la búsqueda y filtros";
    message = "Intenta cambiar la búsqueda, limpiar filtros o seleccionar otras opciones.";
  } else if (hasProjects && hasSearch) {
    title = "Nada coincide con la búsqueda";
    message = "Intenta cambiar la búsqueda o borrar el texto escrito.";
  } else if (hasProjects && hasAdvancedFilters) {
    title = "Nada coincide con los filtros";
    message = "Intenta limpiar filtros o seleccionar otras opciones.";
  } else if (hasProjects && filter === "abiertos") {
    title = "No hay proyectos activos";
    message = "Cuando se cree un proyecto nuevo, aparecerá en esta pestaña.";
  } else if (hasProjects && filter === "cerrados") {
    title = "No hay proyectos cerrados";
    message = "Cuando el Director Creativo asigne un estatus a un proyecto, aparecerá aquí.";
  } else if (hasProjects) {
    title = "Nada coincide con el filtro";
    message = "Intenta quitar el filtro o cambiar la búsqueda.";
  }

  return (
    <div className="text-center py-24 rounded-2xl border border-dashed border-border bg-card/40">
      <div className="w-14 h-14 rounded-2xl bg-primary/10 mx-auto flex items-center justify-center mb-4">
        <LayoutGrid className="w-6 h-6 text-primary" />
      </div>
      <h3 className="text-lg font-semibold">{title}</h3>
      <p className="text-sm text-muted-foreground mt-1 max-w-sm mx-auto">{message}</p>
      {!hasProjects && (
        <Button onClick={onNew} className="mt-5 gap-1.5 rounded-full">
          <Plus className="w-4 h-4" /> Crear proyecto
        </Button>
      )}
    </div>
  );
}
