"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useSession } from "next-auth/react";
import InitiativeDrawer from "@/components/marketing/InitiativeDrawer";
import EmployeePerformanceTable from "@/components/marketing/EmployeePerformanceTable";
import MeetingsWidget from "@/components/marketing/MeetingsWidget";
import {
  formatCurrency,
  formatDate,
  getStatusPillClass,
  INITIATIVE_TYPE_LABELS,
  MILESTONE_STATUS_LABELS,
  TASK_STATUS_LABELS,
} from "@/lib/marketing/labels";
import { cn } from "@/lib/utils";
import {
  initiativeScore,
  projectsMockData,
  type Employee,
  type Initiative,
  type Meeting,
  type Milestone,
  type ProjectRole,
  type Task,
  type TaskStatus,
} from "@/lib/projects";
import { PROJECT_DATE_RANGE_LABELS, PROJECT_ROLE_LABELS, PROJECT_STAGE_LABELS } from "@/lib/projects/labels";
import { useProjectsUIStore } from "@/stores/projectsUIStore";

const NOW = new Date("2026-03-04T12:00:00-06:00").getTime();
const DAY_MS = 24 * 60 * 60 * 1000;
const TASK_COLUMNS: TaskStatus[] = ["todo", "in_progress", "blocked", "done"];

type TaskDraft = {
  status: TaskStatus;
  blockerNote: string;
  dueDateRequest: string;
  evidenceUrl: string;
};

type FeedbackToast = {
  kind: "success" | "error";
  message: string;
};

type SaveActivityCard = {
  id: string;
  title: string;
  detail: string;
};

function toProjectRole(role: string): ProjectRole {
  if (role === "owner") {
    return "owner";
  }

  if (role === "lead" || role === "leader") {
    return "lead";
  }

  return "employee";
}

function addDays(base: number, days: number): string {
  return new Date(base + days * DAY_MS).toISOString().slice(0, 10);
}

function matchesDateRange(initiative: Initiative, range: "7d" | "30d" | "qtd"): boolean {
  const referenceDate = new Date(initiative.completedAt ?? initiative.dueDate).getTime();

  if (range === "7d") {
    return Math.abs(referenceDate - NOW) <= 7 * DAY_MS;
  }

  if (range === "30d") {
    return Math.abs(referenceDate - NOW) <= 30 * DAY_MS;
  }

  const year = new Date(NOW).getUTCFullYear();
  const quarterStart = Date.UTC(year, 0, 1);
  const quarterEnd = Date.UTC(year, 2, 31, 23, 59, 59);
  return referenceDate >= quarterStart && referenceDate <= quarterEnd;
}

function matchesLocationScope(initiative: Initiative, selectedLocationId: "all" | string): boolean {
  if (selectedLocationId === "all") {
    return true;
  }

  return initiative.isGlobal || initiative.locationIds.includes(selectedLocationId);
}

function plannedRevenue(initiative: Initiative): number {
  return initiative.plannedRevenue;
}

function actualRevenue(initiative: Initiative): number {
  return initiative.actualRevenue;
}

function plannedCost(initiative: Initiative): number {
  return initiative.plannedCost;
}

function actualCost(initiative: Initiative): number {
  return initiative.actualCost;
}

function costVariancePct(initiative: Initiative): number {
  return initiative.costVariancePct;
}

function actualProfit(initiative: Initiative): number {
  return initiative.actualProfit;
}

function actualMarginPct(initiative: Initiative): number {
  return initiative.actualMarginPct;
}

function average(values: number[]): number {
  if (values.length === 0) {
    return 0;
  }

  return values.reduce((acc, value) => acc + value, 0) / values.length;
}

export default function ProjectsDepartmentPage() {
  const { data: session } = useSession();
  const { locationId, dateRange, setLocationId, setDateRange } = useProjectsUIStore();

  const [employees, setEmployees] = useState<Employee[]>(projectsMockData.employees);
  const [initiatives, setInitiatives] = useState<Initiative[]>(projectsMockData.initiatives);
  const [tasks, setTasks] = useState<Task[]>(projectsMockData.tasks);
  const [meetings, setMeetings] = useState<Meeting[]>(projectsMockData.meetings);
  const [selectedInitiativeId, setSelectedInitiativeId] = useState<string | null>(null);
  const [isLoadingProjects, setIsLoadingProjects] = useState(true);
  const [isCreatingInitiative, setIsCreatingInitiative] = useState(false);
  const [deletingInitiativeId, setDeletingInitiativeId] = useState<string | null>(null);
  const [isSavingMeeting, setIsSavingMeeting] = useState(false);
  const [projectsError, setProjectsError] = useState<string | null>(null);
  const [meetingsError, setMeetingsError] = useState<string | null>(null);
  const [feedbackToast, setFeedbackToast] = useState<FeedbackToast | null>(null);
  const [saveActivityCards, setSaveActivityCards] = useState<SaveActivityCard[]>([]);
  const [taskDrafts, setTaskDrafts] = useState<Record<string, TaskDraft>>({});
  const [milestoneTitle, setMilestoneTitle] = useState("");
  const [milestoneDescription, setMilestoneDescription] = useState("");
  const [milestoneDueDate, setMilestoneDueDate] = useState("");
  const feedbackTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  const normalizedRole = toProjectRole(session?.user?.role ?? "");
  const canManage = normalizedRole === "owner" || normalizedRole === "lead";

  const employeesById = useMemo(() => Object.fromEntries(employees.map((employee) => [employee.id, employee])), [employees]);
  const locationsById = useMemo(() => Object.fromEntries(projectsMockData.locations.map((location) => [location.id, location])), []);
  const tasksById = useMemo(() => Object.fromEntries(tasks.map((task) => [task.id, task])), [tasks]);

  const filteredInitiatives = useMemo(
    () =>
      initiatives.filter((initiative) => {
        const matchesLocation = matchesLocationScope(initiative, locationId);
        const matchesRange = matchesDateRange(initiative, dateRange);
        return matchesLocation && matchesRange;
      }),
    [dateRange, initiatives, locationId]
  );

  const filteredTaskSet = useMemo(() => new Set(filteredInitiatives.map((initiative) => initiative.id)), [filteredInitiatives]);
  const filteredTasks = useMemo(() => tasks.filter((task) => filteredTaskSet.has(task.initiativeId)), [filteredTaskSet, tasks]);

  const boardTasks = useMemo(() => {
    if (normalizedRole !== "employee") {
      return filteredTasks;
    }

    return filteredTasks.filter((task) => task.assigneeId === session?.user?.id);
  }, [filteredTasks, normalizedRole, session?.user?.id]);

  const participantOptions = useMemo(() => Array.from(new Set(employees.map((employee) => employee.name))), [employees]);
  const pushFeedback = useCallback((kind: FeedbackToast["kind"], message: string) => {
    setFeedbackToast({ kind, message });
  }, []);
  const pushSaveCard = useCallback((title: string, detail: string) => {
    const id = `${Date.now()}-${Math.random().toString(16).slice(2)}`;
    setSaveActivityCards((prev) => [{ id, title, detail }, ...prev].slice(0, 4));

    setTimeout(() => {
      setSaveActivityCards((prev) => prev.filter((item) => item.id !== id));
    }, 6200);
  }, []);

  useEffect(() => {
    if (!feedbackToast) {
      return;
    }

    if (feedbackTimeoutRef.current) {
      clearTimeout(feedbackTimeoutRef.current);
    }

    feedbackTimeoutRef.current = setTimeout(() => {
      setFeedbackToast(null);
      feedbackTimeoutRef.current = null;
    }, 2800);

    return () => {
      if (feedbackTimeoutRef.current) {
        clearTimeout(feedbackTimeoutRef.current);
      }
    };
  }, [feedbackToast]);

  const selectedInitiative = useMemo(
    () => initiatives.find((initiative) => initiative.id === selectedInitiativeId) ?? null,
    [initiatives, selectedInitiativeId]
  );

  const selectedTimeline = useMemo(() => {
    if (!selectedInitiative) {
      return [] as Array<{ at: string; label: string }>;
    }

    const timeline: Array<{ at: string; label: string }> = [];

    if (selectedInitiative.updatedAt) {
      timeline.push({
        at: selectedInitiative.updatedAt,
        label: `Actualización general (${selectedInitiative.updatedByName ?? "equipo"})`,
      });
    }

    for (const milestone of selectedInitiative.milestones ?? []) {
      for (const checkpoint of milestone.checkpoints) {
        timeline.push({
          at: checkpoint.createdAt,
          label: `Checkpoint en "${milestone.title}": ${checkpoint.note}`,
        });
      }
    }

    return timeline
      .sort((a, b) => new Date(b.at).getTime() - new Date(a.at).getTime())
      .slice(0, 12);
  }, [selectedInitiative]);

  const initiativeScoresById = useMemo(
    () =>
      Object.fromEntries(
        filteredInitiatives.map((initiative) => {
          return [initiative.id, initiativeScore(initiative)];
        })
      ),
    [filteredInitiatives]
  );

  const allMilestones = useMemo(() => filteredInitiatives.flatMap((initiative) => initiative.milestones ?? []), [filteredInitiatives]);
  const activeProjects = useMemo(
    () => filteredInitiatives.filter((initiative) => initiative.status !== "results" && initiative.status !== "evaluation").length,
    [filteredInitiatives]
  );
  const onTimeMilestonePct = useMemo(() => {
    if (allMilestones.length === 0) {
      return 0;
    }

    const onTimeCount = allMilestones.filter((milestone) => {
      if (milestone.status === "completed") {
        return true;
      }

      return new Date(milestone.dueDate).getTime() >= NOW;
    }).length;

    return (onTimeCount / allMilestones.length) * 100;
  }, [allMilestones]);
  const blockedTasksCount = useMemo(() => filteredTasks.filter((task) => task.status === "blocked").length, [filteredTasks]);
  const overdueTasksCount = useMemo(
    () => filteredTasks.filter((task) => task.status !== "done" && new Date(task.dueDate).getTime() < NOW).length,
    [filteredTasks]
  );
  const actualPhaseInitiatives = useMemo(
    () =>
      filteredInitiatives.filter((initiative) => {
        const hasActualValues = actualRevenue(initiative) > 0 || actualCost(initiative) > 0;
        const isActualStage = initiative.status === "completion" || initiative.status === "results" || initiative.status === "evaluation";
        return hasActualValues || isActualStage;
      }),
    [filteredInitiatives]
  );
  const costVariancePctTotal = useMemo(() => {
    const planned = actualPhaseInitiatives.reduce((acc, initiative) => acc + plannedCost(initiative), 0);
    const actual = actualPhaseInitiatives.reduce((acc, initiative) => acc + actualCost(initiative), 0);
    if (planned <= 0) {
      return 0;
    }

    return ((actual - planned) / planned) * 100;
  }, [actualPhaseInitiatives]);
  const averageInitiativeMarginPct = useMemo(() => {
    const margins = actualPhaseInitiatives
      .map((initiative) => actualMarginPct(initiative))
      .filter((value) => Number.isFinite(value));

    if (margins.length === 0) {
      return 0;
    }

    return average(margins);
  }, [actualPhaseInitiatives]);

  const alertItems = useMemo(() => {
    const blocked = filteredTasks
      .filter((task) => task.status === "blocked")
      .slice(0, 5)
      .map((task) => ({ id: `blocked:${task.id}`, title: `Bloqueada: ${task.title}`, detail: `Responsable: ${employeesById[task.assigneeId]?.name ?? "Sin asignar"}` }));

    const overdueMilestones = allMilestones
      .filter((milestone) => milestone.status !== "completed" && new Date(milestone.dueDate).getTime() < NOW)
      .slice(0, 5)
      .map((milestone) => ({ id: `milestone:${milestone.id}`, title: `Hito vencido: ${milestone.title}`, detail: `Fecha: ${formatDate(milestone.dueDate)}` }));

    const budgetRisks = filteredInitiatives
      .map((initiative) => ({ initiative, variance: costVariancePct(initiative) }))
      .filter((item) => item.variance >= 10)
      .slice(0, 5)
      .map((item) => ({
        id: `budget:${item.initiative.id}`,
        title: `Sobregasto: ${item.initiative.name}`,
        detail: `Variación de costo: ${item.variance.toFixed(1)}%`,
      }));

    return [...blocked, ...overdueMilestones, ...budgetRisks].slice(0, 12);
  }, [allMilestones, employeesById, filteredInitiatives, filteredTasks]);

  useEffect(() => {
    if (!selectedInitiativeId) {
      return;
    }

    const stillExists = initiatives.some((initiative) => initiative.id === selectedInitiativeId);
    if (!stillExists) {
      setSelectedInitiativeId(null);
    }
  }, [initiatives, selectedInitiativeId]);

  const loadProjectsData = useCallback(async (options?: { showLoading?: boolean }) => {
    const shouldShowLoading = options?.showLoading ?? true;
    if (shouldShowLoading) {
      setIsLoadingProjects(true);
    }

    try {
      const response = await fetch("/api/projects/dashboard", {
        method: "GET",
        cache: "no-store",
      });

      const payload = (await response.json()) as {
        error?: string;
        employees?: Employee[];
        initiatives?: Initiative[];
        tasks?: Task[];
      };

      if (!response.ok) {
        throw new Error(payload.error ?? "No se pudo cargar Projects.");
      }

      setEmployees(payload.employees ?? []);
      setInitiatives(payload.initiatives ?? []);
      setTasks(payload.tasks ?? []);
      setProjectsError(null);
    } catch (error) {
      setProjectsError(error instanceof Error ? error.message : "No se pudo cargar Projects.");
    } finally {
      if (shouldShowLoading) {
        setIsLoadingProjects(false);
      }
    }
  }, []);

  const loadMeetings = useCallback(async () => {
    const response = await fetch("/api/projects/meetings", {
      method: "GET",
      cache: "no-store",
    });

    if (!response.ok) {
      const payload = (await response.json()) as { error?: string };
      throw new Error(payload.error ?? "No se pudieron cargar reuniones.");
    }

    const payload = (await response.json()) as { meetings: Meeting[] };
    setMeetings(payload.meetings);
    setMeetingsError(null);
  }, []);

  useEffect(() => {
    loadProjectsData().catch(() => {
      // handled in callback
    });

    loadMeetings().catch((error) => {
      setMeetingsError(error instanceof Error ? error.message : "No se pudieron cargar reuniones.");
    });
  }, [loadMeetings, loadProjectsData]);

  const handleCreateInitiative = () => {
    if (isCreatingInitiative) {
      return;
    }

    const isGlobal = locationId === "all";
    const locationScope = isGlobal ? [] : [locationId];
    const defaultDueInDays = dateRange === "7d" ? 6 : dateRange === "30d" ? 14 : 21;

    void (async () => {
      setIsCreatingInitiative(true);
      setProjectsError(null);
      try {
        const response = await fetch("/api/projects/initiatives", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            name: "Nuevo proyecto",
            type: "otro",
            dueDate: addDays(NOW, defaultDueInDays),
            isGlobal,
            locationIds: locationScope,
            metricSelection: {
              score: true,
              tickets: false,
              revenue: true,
            },
          }),
        });

        const payload = (await response.json()) as { error?: string; initiative?: Initiative };
        if (!response.ok) {
          throw new Error(payload.error ?? "No se pudo crear el proyecto.");
        }

        if (payload.initiative?.id) {
          setInitiatives((prev) => [payload.initiative!, ...prev.filter((initiative) => initiative.id !== payload.initiative!.id)]);
          setSelectedInitiativeId(payload.initiative.id);
        }

        pushFeedback("success", "Proyecto creado.");
        pushSaveCard("Proyecto creado", payload.initiative?.name ?? "Nuevo proyecto");
        void loadProjectsData();
      } catch (error) {
        const message = error instanceof Error ? error.message : "No se pudo crear el proyecto.";
        setProjectsError(message);
        pushFeedback("error", message);
      } finally {
        setIsCreatingInitiative(false);
      }
    })();
  };

  const handleSaveInitiative = async (nextInitiative: unknown): Promise<boolean> => {
    const safeInitiative = nextInitiative as Initiative;
    try {
      const response = await fetch(`/api/projects/initiatives/${safeInitiative.id}`, {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ initiative: safeInitiative }),
      });

      const payload = (await response.json()) as { error?: string; initiative?: Initiative };
      if (!response.ok) {
        throw new Error(payload.error ?? "No se pudo guardar el proyecto.");
      }

      setInitiatives((prev) =>
        prev.map((initiative) => (initiative.id === safeInitiative.id ? payload.initiative ?? safeInitiative : initiative))
      );

      void loadProjectsData({ showLoading: false });
      pushFeedback("success", "Proyecto guardado correctamente.");
      pushSaveCard("Guardado confirmado", `${safeInitiative.name} · etapa ${PROJECT_STAGE_LABELS[safeInitiative.status]}`);
      return true;
    } catch (error) {
      const message = error instanceof Error ? error.message : "No se pudo guardar el proyecto.";
      setProjectsError(message);
      pushFeedback("error", message);
      return false;
    }
  };

  const handleDeleteInitiative = (initiativeId: string) => {
    if (deletingInitiativeId === initiativeId) {
      return;
    }

    const confirmed = window.confirm("¿Eliminar este proyecto? Esta acción también elimina tareas y milestones ligados.");
    if (!confirmed) {
      return;
    }

    void (async () => {
      setDeletingInitiativeId(initiativeId);
      setProjectsError(null);
      try {
        const response = await fetch(`/api/projects/initiatives/${initiativeId}`, {
          method: "DELETE",
        });

        const payload = (await response.json()) as { error?: string };
        if (!response.ok) {
          throw new Error(payload.error ?? "No se pudo eliminar el proyecto.");
        }

        setInitiatives((prev) => prev.filter((initiative) => initiative.id !== initiativeId));
        setTasks((prev) => prev.filter((task) => task.initiativeId !== initiativeId));
        if (selectedInitiativeId === initiativeId) {
          setSelectedInitiativeId(null);
        }

        pushFeedback("success", "Proyecto eliminado.");
        void loadProjectsData();
      } catch (error) {
        const message = error instanceof Error ? error.message : "No se pudo eliminar el proyecto.";
        setProjectsError(message);
        pushFeedback("error", message);
      } finally {
        setDeletingInitiativeId(null);
      }
    })();
  };

  const handleUpdateTask = (taskId: string, patch: Partial<Pick<Task, "status" | "evidenceLinks">>) => {
    void (async () => {
      try {
        const response = await fetch(`/api/projects/tasks/${taskId}`, {
          method: "PATCH",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(patch),
        });

        const payload = (await response.json()) as { error?: string; task?: Task };
        if (!response.ok) {
          throw new Error(payload.error ?? "No se pudo actualizar la tarea.");
        }

        if (payload.task) {
          setTasks((prev) => prev.map((task) => (task.id === payload.task?.id ? payload.task : task)));
          pushFeedback("success", "Tarea actualizada.");
          pushSaveCard("Tarea guardada", `${payload.task.title} · ${TASK_STATUS_LABELS[payload.task.status]}`);
        }
      } catch (error) {
        const message = error instanceof Error ? error.message : "No se pudo actualizar la tarea.";
        setProjectsError(message);
        pushFeedback("error", message);
      }
    })();
  };

  const handleCreateTask = (input: { initiativeId: string; title: string; description: string; assigneeId: string; dueDate: string }) => {
    void (async () => {
      try {
        const response = await fetch("/api/projects/tasks", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(input),
        });

        const payload = (await response.json()) as { error?: string; task?: Task };
        if (!response.ok) {
          throw new Error(payload.error ?? "No se pudo crear la tarea.");
        }

        if (payload.task) {
          setTasks((prev) => [...prev, payload.task as Task]);
          setInitiatives((prev) =>
            prev.map((initiative) =>
              initiative.id === input.initiativeId
                ? {
                    ...initiative,
                    taskIds: [...initiative.taskIds, payload.task!.id],
                  }
                : initiative
            )
          );
          pushFeedback("success", "Tarea creada.");
          pushSaveCard("Tarea creada", payload.task.title);
        }
      } catch (error) {
        const message = error instanceof Error ? error.message : "No se pudo crear la tarea.";
        setProjectsError(message);
        pushFeedback("error", message);
      }
    })();
  };

  const handleCreateMilestone = (input: { initiativeId: string; title: string; description: string; dueDate: string }) => {
    void (async () => {
      try {
        const response = await fetch(`/api/projects/initiatives/${input.initiativeId}/milestones`, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(input),
        });

        const payload = (await response.json()) as { error?: string; milestone?: Milestone };
        if (!response.ok) {
          throw new Error(payload.error ?? "No se pudo crear el milestone.");
        }

        if (payload.milestone) {
          setInitiatives((prev) =>
            prev.map((initiative) => {
              if (initiative.id !== input.initiativeId) {
                return initiative;
              }

              const nextMilestones = [...(initiative.milestones ?? []), payload.milestone!].sort((a, b) => a.sortOrder - b.sortOrder);

              return {
                ...initiative,
                milestones: nextMilestones,
              };
            })
          );
          setMilestoneTitle("");
          setMilestoneDescription("");
          setMilestoneDueDate("");
          pushFeedback("success", "Hito creado.");
          pushSaveCard("Milestone guardado", `${payload.milestone.title} · vence ${formatDate(payload.milestone.dueDate)}`);
        }
      } catch (error) {
        const message = error instanceof Error ? error.message : "No se pudo crear el milestone.";
        setProjectsError(message);
        pushFeedback("error", message);
      }
    })();
  };

  const handleUpdateMilestone = (milestoneId: string, patch: { status?: "pending" | "in_progress" | "completed" }) => {
    void (async () => {
      try {
        const response = await fetch(`/api/projects/milestones/${milestoneId}`, {
          method: "PATCH",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(patch),
        });

        const payload = (await response.json()) as { error?: string; milestone?: Milestone };
        if (!response.ok) {
          throw new Error(payload.error ?? "No se pudo actualizar el milestone.");
        }

        if (payload.milestone) {
          setInitiatives((prev) =>
            prev.map((initiative) => {
              const milestones = initiative.milestones ?? [];
              if (!milestones.some((milestone) => milestone.id === payload.milestone?.id)) {
                return initiative;
              }

              return {
                ...initiative,
                milestones: milestones
                  .map((milestone) => (milestone.id === payload.milestone?.id ? payload.milestone! : milestone))
                  .sort((a, b) => a.sortOrder - b.sortOrder),
              };
            })
          );
          pushFeedback("success", "Hito actualizado.");
          pushSaveCard("Milestone actualizado", `${payload.milestone.title} · ${MILESTONE_STATUS_LABELS[payload.milestone.status]}`);
        }
      } catch (error) {
        const message = error instanceof Error ? error.message : "No se pudo actualizar el milestone.";
        setProjectsError(message);
        pushFeedback("error", message);
      }
    })();
  };

  const handleAddMilestoneCheckpoint = (input: { milestoneId: string; note: string }) => {
    void (async () => {
      try {
        const response = await fetch(`/api/projects/milestones/${input.milestoneId}/checkpoints`, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ note: input.note }),
        });

        const payload = (await response.json()) as { error?: string; milestone?: Milestone };
        if (!response.ok) {
          throw new Error(payload.error ?? "No se pudo registrar el checkpoint.");
        }

        if (payload.milestone) {
          setInitiatives((prev) =>
            prev.map((initiative) => {
              const milestones = initiative.milestones ?? [];
              if (!milestones.some((milestone) => milestone.id === payload.milestone?.id)) {
                return initiative;
              }

              return {
                ...initiative,
                milestones: milestones
                  .map((milestone) => (milestone.id === payload.milestone?.id ? payload.milestone! : milestone))
                  .sort((a, b) => a.sortOrder - b.sortOrder),
              };
            })
          );
          pushFeedback("success", "Checkpoint guardado.");
          pushSaveCard("Checkpoint guardado", input.note);
        }
      } catch (error) {
        const message = error instanceof Error ? error.message : "No se pudo registrar el checkpoint.";
        setProjectsError(message);
        pushFeedback("error", message);
      }
    })();
  };

  const handleTaskBoardSubmit = (task: Task) => {
    const draft = taskDrafts[task.id] ?? {
      status: task.status,
      blockerNote: "",
      dueDateRequest: "",
      evidenceUrl: "",
    };

    const evidenceLinks = Array.from(
      new Set(
        [...task.evidenceLinks, draft.evidenceUrl]
          .map((value) => value.trim())
          .filter((value) => value.length > 0)
      )
    );

    void (async () => {
      try {
        const response = await fetch(`/api/projects/tasks/${task.id}`, {
          method: "PATCH",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            status: draft.status,
            blockerNote: draft.blockerNote,
            dueDateRequest: draft.dueDateRequest,
            evidenceLinks,
          }),
        });

        const payload = (await response.json()) as { error?: string; task?: Task };
        if (!response.ok) {
          throw new Error(payload.error ?? "No se pudo actualizar la tarea.");
        }

        const nextTask = payload.task;
        if (nextTask) {
          setTasks((prev) => prev.map((item) => (item.id === nextTask.id ? nextTask : item)));
          setTaskDrafts((prev) => ({
            ...prev,
            [task.id]: {
              status: nextTask.status,
              blockerNote: "",
              dueDateRequest: "",
              evidenceUrl: "",
            },
          }));
          pushFeedback("success", "Actualización de tarea guardada.");
          pushSaveCard("Tarea guardada", `${nextTask.title} · ${TASK_STATUS_LABELS[nextTask.status]}`);
        }
      } catch (error) {
        const message = error instanceof Error ? error.message : "No se pudo actualizar la tarea.";
        setProjectsError(message);
        pushFeedback("error", message);
      }
    })();
  };

  const handleRequestMeeting = async (input: {
    title: string;
    agenda: string;
    suggestedTimes: string[];
    participantNames: string[];
  }) => {
    setIsSavingMeeting(true);
    try {
      const response = await fetch("/api/projects/meetings", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          kind: "request",
          ...input,
        }),
      });

      if (!response.ok) {
        const payload = (await response.json()) as { error?: string };
        throw new Error(payload.error ?? "No se pudo solicitar reunión.");
      }

      await loadMeetings();
      setMeetingsError(null);
      pushFeedback("success", "Solicitud de reunión enviada.");
    } catch (error) {
      const message = error instanceof Error ? error.message : "No se pudo solicitar reunión.";
      setMeetingsError(message);
      pushFeedback("error", message);
    } finally {
      setIsSavingMeeting(false);
    }
  };

  const handleScheduleMeeting = async (input: {
    title: string;
    agenda: string;
    scheduledFor: string;
    participantNames: string[];
  }) => {
    setIsSavingMeeting(true);
    try {
      const response = await fetch("/api/projects/meetings", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          kind: "schedule",
          ...input,
        }),
      });

      if (!response.ok) {
        const payload = (await response.json()) as { error?: string };
        throw new Error(payload.error ?? "No se pudo agendar reunión.");
      }

      await loadMeetings();
      setMeetingsError(null);
      pushFeedback("success", "Reunión agendada.");
    } catch (error) {
      const message = error instanceof Error ? error.message : "No se pudo agendar reunión.";
      setMeetingsError(message);
      pushFeedback("error", message);
    } finally {
      setIsSavingMeeting(false);
    }
  };

  const handleCompleteMeeting = async (input: {
    meetingId: string;
    commitments: Array<{
      title: string;
      description?: string;
      ownerName?: string;
      dueDate?: string;
    }>;
  }) => {
    setIsSavingMeeting(true);
    try {
      const response = await fetch(`/api/projects/meetings/${input.meetingId}`, {
        method: "PATCH",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          action: "complete",
          commitments: input.commitments,
        }),
      });

      if (!response.ok) {
        const payload = (await response.json()) as { error?: string };
        throw new Error(payload.error ?? "No se pudo completar reunión.");
      }

      await loadMeetings();
      setMeetingsError(null);
      pushFeedback("success", "Reunión completada.");
    } catch (error) {
      const message = error instanceof Error ? error.message : "No se pudo completar reunión.";
      setMeetingsError(message);
      pushFeedback("error", message);
    } finally {
      setIsSavingMeeting(false);
    }
  };

  const subtitleDateRange = PROJECT_DATE_RANGE_LABELS[dateRange];

  return (
    <div className="space-y-5">
      <header className="rounded-benell border border-benell-stroke bg-benell-surface p-5 shadow-benell">
        <div className="flex flex-wrap items-end justify-between gap-4">
          <div>
            <h1 className="text-display">Projects</h1>
            <p className="text-body mt-1 text-benell-text-soft">Eventos / Proyectos. Planeación, ejecución y control operativo.</p>
          </div>

          <div className="grid w-full gap-3 sm:grid-cols-4 lg:w-auto lg:min-w-[860px]">
            <label className="block space-y-1">
              <span className="text-label font-semibold">Rango</span>
              <select
                value={dateRange}
                onChange={(event) => setDateRange(event.target.value as "7d" | "30d" | "qtd")}
                className="text-body w-full rounded-xl border border-benell-stroke bg-white px-3 py-2 outline-none focus-visible:ring-2 focus-visible:ring-benell-brown"
              >
                {Object.entries(PROJECT_DATE_RANGE_LABELS).map(([value, label]) => (
                  <option key={value} value={value}>
                    {label}
                  </option>
                ))}
              </select>
            </label>

            <label className="block space-y-1">
              <span className="text-label font-semibold">Ubicación</span>
              <select
                value={locationId}
                onChange={(event) => setLocationId(event.target.value)}
                className="text-body w-full rounded-xl border border-benell-stroke bg-white px-3 py-2 outline-none focus-visible:ring-2 focus-visible:ring-benell-brown"
              >
                <option value="all">Todas</option>
                {projectsMockData.locations.map((location) => (
                  <option key={location.id} value={location.id}>
                    {location.name}
                  </option>
                ))}
              </select>
            </label>

            <label className="block space-y-1">
              <span className="text-label font-semibold">Vista</span>
              <div className="text-body w-full rounded-xl border border-benell-stroke bg-white px-3 py-2 text-benell-text-soft">
                {PROJECT_ROLE_LABELS[normalizedRole]}
              </div>
            </label>

            <button
              type="button"
              onClick={handleCreateInitiative}
              disabled={!canManage || isCreatingInitiative}
              className="rounded-pill bg-benell-brown px-4 py-2 text-label font-semibold text-white disabled:cursor-not-allowed disabled:opacity-60"
            >
              {isCreatingInitiative ? "Creando..." : "Nuevo proyecto"}
            </button>
          </div>
        </div>
      </header>

      <p className="text-label px-1 text-benell-text-soft">
        Mostrando {filteredInitiatives.length} proyectos para {locationId === "all" ? "todas las ubicaciones" : locationsById[locationId]?.name} · {subtitleDateRange}
      </p>

      {projectsError ? <p className="text-label text-benell-red">{projectsError}</p> : null}
      {isLoadingProjects ? <p className="text-label text-benell-text-soft">Cargando projects...</p> : null}

      <section className="overflow-x-auto">
        <div className="grid min-w-[1320px] grid-cols-6 gap-3">
        <article className="rounded-benell border border-benell-stroke bg-benell-surface p-4 shadow-benell">
          <p className="text-label text-benell-text-soft">Proyectos activos</p>
          <p className="text-h1 mt-1">{activeProjects}</p>
        </article>
        <article className="rounded-benell border border-benell-stroke bg-benell-surface p-4 shadow-benell">
          <p className="text-label text-benell-text-soft">Hitos a tiempo</p>
          <p className="text-h1 mt-1 text-tabular">{onTimeMilestonePct.toFixed(1)}%</p>
        </article>
        <article className="rounded-benell border border-benell-stroke bg-benell-surface p-4 shadow-benell">
          <p className="text-label text-benell-text-soft">Tareas bloqueadas</p>
          <p className="text-h1 mt-1 text-benell-red">{blockedTasksCount}</p>
        </article>
        <article className="rounded-benell border border-benell-stroke bg-benell-surface p-4 shadow-benell">
          <p className="text-label text-benell-text-soft">Tareas vencidas</p>
          <p className="text-h1 mt-1 text-benell-red">{overdueTasksCount}</p>
        </article>
        <article className="rounded-benell border border-benell-stroke bg-benell-surface p-4 shadow-benell">
          <p className="text-label text-benell-text-soft">Variación de costo</p>
          <p
            className={cn(
              "text-h1 mt-1 text-tabular",
              costVariancePctTotal > 0 ? "text-benell-red" : costVariancePctTotal < 0 ? "text-benell-green" : "text-benell-text"
            )}
          >
            {costVariancePctTotal.toFixed(1)}%
          </p>
        </article>
          <article className="rounded-benell border border-benell-stroke bg-benell-surface p-4 shadow-benell">
            <p className="text-label text-benell-text-soft">Margen promedio</p>
            <p
              className={cn(
                "text-h1 mt-1 text-tabular",
                averageInitiativeMarginPct > 0
                  ? "text-benell-green"
                  : averageInitiativeMarginPct < 0
                    ? "text-benell-red"
                    : "text-benell-text"
              )}
            >
              {averageInitiativeMarginPct.toFixed(1)}%
            </p>
          </article>
        </div>
      </section>

      <section className="rounded-benell border border-benell-stroke bg-benell-surface p-5 shadow-benell">
        <h2 className="text-h2 font-semibold">Alertas operativas</h2>
        <div className="mt-3 grid gap-2 md:grid-cols-2">
          {alertItems.length > 0 ? (
            alertItems.map((alert) => (
              <article key={alert.id} className="rounded-xl border border-benell-stroke bg-white p-3">
                <p className="text-body font-semibold">{alert.title}</p>
                <p className="text-label mt-1 text-benell-text-soft">{alert.detail}</p>
              </article>
            ))
          ) : (
            <p className="text-body text-benell-text-soft">Sin alertas críticas para el rango actual.</p>
          )}
        </div>
      </section>

      <section className="rounded-benell border border-benell-stroke bg-benell-surface p-5 shadow-benell">
        <h2 className="text-h2 font-semibold">Portfolio de proyectos</h2>
        <p className="text-label mt-1 text-benell-text-soft">Selecciona una fila para abrir detalle y edición completa.</p>
        <div className="mt-4 overflow-x-auto">
          <table className="min-w-[1660px] w-full border-separate border-spacing-y-2">
            <thead>
              <tr className="text-left text-label text-benell-text-soft">
                <th className="px-3 py-1">Proyecto</th>
                <th className="px-3 py-1">Tipo</th>
                <th className="px-3 py-1">Líder</th>
                <th className="px-3 py-1">Fecha compromiso</th>
                <th className="px-3 py-1">Etapa</th>
                <th className="px-3 py-1">Salud</th>
                <th className="px-3 py-1">Revenue planeado</th>
                <th className="px-3 py-1">Revenue actual</th>
                <th className="px-3 py-1">Costo planeado</th>
                <th className="px-3 py-1">Costo actual</th>
                <th className="px-3 py-1">Utilidad actual</th>
                <th className="px-3 py-1">Margen actual</th>
              </tr>
            </thead>
            <tbody>
              {filteredInitiatives.map((initiative) => {
                const isSelected = selectedInitiativeId === initiative.id;
                const health = initiativeScoresById[initiative.id] ?? 0;

                return (
                  <tr
                    key={initiative.id}
                    onClick={() => setSelectedInitiativeId(initiative.id)}
                    className={cn(
                      "cursor-pointer rounded-xl bg-white transition hover:bg-benell-surface-muted",
                      isSelected ? "ring-2 ring-benell-brown" : ""
                    )}
                  >
                    <td className="rounded-l-xl px-3 py-3 text-body font-semibold">{initiative.name}</td>
                    <td className="px-3 py-3 text-body">{INITIATIVE_TYPE_LABELS[initiative.type]}</td>
                    <td className="px-3 py-3 text-body">{employeesById[initiative.ownerId]?.name ?? "Sin líder"}</td>
                    <td className="px-3 py-3 text-body text-tabular">{formatDate(initiative.dueDate)}</td>
                    <td className="px-3 py-3 text-body">
                      <span className={`rounded-pill px-2 py-1 text-label font-semibold ${getStatusPillClass(initiative.status)}`}>
                        {PROJECT_STAGE_LABELS[initiative.status]}
                      </span>
                    </td>
                    <td className="px-3 py-3 text-body text-tabular">{health.toFixed(1)}</td>
                    <td className="px-3 py-3 text-body text-tabular">{formatCurrency(plannedRevenue(initiative))}</td>
                    <td className="px-3 py-3 text-body text-tabular">{formatCurrency(actualRevenue(initiative))}</td>
                    <td className="px-3 py-3 text-body text-tabular">{formatCurrency(plannedCost(initiative))}</td>
                    <td className="px-3 py-3 text-body text-tabular">{formatCurrency(actualCost(initiative))}</td>
                    <td className={cn("px-3 py-3 text-body text-tabular font-semibold", actualProfit(initiative) >= 0 ? "text-benell-green" : "text-benell-red")}>
                      {formatCurrency(actualProfit(initiative))}
                    </td>
                    <td className={cn("rounded-r-xl px-3 py-3 text-body text-tabular font-semibold", actualMarginPct(initiative) >= 0 ? "text-benell-green" : "text-benell-red")}>
                      {actualMarginPct(initiative).toFixed(1)}%
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
        {filteredInitiatives.length === 0 ? <p className="text-body mt-3 text-benell-text-soft">No hay proyectos para los filtros seleccionados.</p> : null}
      </section>

      <div className="grid gap-5 xl:grid-cols-2">
        <section className="rounded-benell border border-benell-stroke bg-benell-surface p-5 shadow-benell">
          <h2 className="text-h2 font-semibold">Milestones</h2>
          {selectedInitiative ? (
            <>
              <p className="text-label mt-1 text-benell-text-soft">Proyecto seleccionado: {selectedInitiative.name}</p>
              {canManage ? (
                <form
                  className="mt-3 grid gap-2 md:grid-cols-3"
                  onSubmit={(event) => {
                    event.preventDefault();
                    if (!milestoneTitle.trim() || !milestoneDueDate) {
                      return;
                    }

                    handleCreateMilestone({
                      initiativeId: selectedInitiative.id,
                      title: milestoneTitle.trim(),
                      description: milestoneDescription.trim(),
                      dueDate: milestoneDueDate,
                    });
                  }}
                >
                  <input
                    value={milestoneTitle}
                    onChange={(event) => setMilestoneTitle(event.target.value)}
                    placeholder="Nuevo milestone"
                    className="text-body rounded-xl border border-benell-stroke bg-white px-3 py-2"
                  />
                  <input
                    type="date"
                    value={milestoneDueDate}
                    onChange={(event) => setMilestoneDueDate(event.target.value)}
                    className="text-body rounded-xl border border-benell-stroke bg-white px-3 py-2"
                  />
                  <button type="submit" className="rounded-pill bg-benell-brown px-3 py-2 text-label font-semibold text-white">
                    Agregar hito
                  </button>
                  <textarea
                    value={milestoneDescription}
                    onChange={(event) => setMilestoneDescription(event.target.value)}
                    placeholder="Descripción"
                    className="text-body md:col-span-3 rounded-xl border border-benell-stroke bg-white px-3 py-2"
                    rows={2}
                  />
                </form>
              ) : null}

              <div className="mt-3 space-y-2">
                {(selectedInitiative.milestones ?? []).length > 0 ? (
                  (selectedInitiative.milestones ?? []).map((milestone) => (
                    <article key={milestone.id} className="rounded-xl border border-benell-stroke bg-white p-3">
                      <div className="flex flex-wrap items-center justify-between gap-2">
                        <p className="text-body font-semibold">{milestone.title}</p>
                        <span className={`rounded-pill px-2 py-1 text-label font-semibold ${getStatusPillClass(milestone.status)}`}>
                          {MILESTONE_STATUS_LABELS[milestone.status]}
                        </span>
                      </div>
                      <p className="text-label mt-1 text-benell-text-soft">{formatDate(milestone.dueDate)}</p>
                      {canManage ? (
                        <div className="mt-2 flex flex-wrap gap-2">
                          {(["pending", "in_progress", "completed"] as const).map((status) => (
                            <button
                              key={status}
                              type="button"
                              onClick={() => handleUpdateMilestone(milestone.id, { status })}
                              className={cn(
                                "rounded-pill border px-2 py-1 text-label",
                                milestone.status === status
                                  ? "border-benell-brown bg-benell-brown text-white"
                                  : "border-benell-stroke bg-white text-benell-text"
                              )}
                            >
                              {MILESTONE_STATUS_LABELS[status]}
                            </button>
                          ))}
                        </div>
                      ) : null}
                    </article>
                  ))
                ) : (
                  <p className="text-body text-benell-text-soft">Este proyecto no tiene hitos registrados.</p>
                )}
              </div>
            </>
          ) : (
            <p className="text-body mt-2 text-benell-text-soft">Selecciona un proyecto para ver y gestionar hitos.</p>
          )}
        </section>

        <section className="rounded-benell border border-benell-stroke bg-benell-surface p-5 shadow-benell">
          <h2 className="text-h2 font-semibold">Board de tareas</h2>
          <p className="text-label mt-1 text-benell-text-soft">
            {normalizedRole === "employee" ? "Mostrando solo tus tareas asignadas." : "Mostrando tareas del portafolio filtrado."}
          </p>
          <div className="mt-3 grid gap-3 xl:grid-cols-2">
            {TASK_COLUMNS.map((column) => {
              const items = boardTasks.filter((task) => task.status === column);
              return (
                <article key={column} className="rounded-xl border border-benell-stroke bg-white p-3">
                  <div className="mb-2 flex items-center justify-between">
                    <p className="text-body font-semibold">{TASK_STATUS_LABELS[column]}</p>
                    <span className="text-label rounded-pill bg-benell-surface-muted px-2 py-0.5">{items.length}</span>
                  </div>
                  <div className="space-y-2">
                    {items.map((task) => {
                      const canEditTask = canManage || task.assigneeId === session?.user?.id;
                      const draft = taskDrafts[task.id] ?? {
                        status: task.status,
                        blockerNote: "",
                        dueDateRequest: "",
                        evidenceUrl: "",
                      };

                      return (
                        <div key={task.id} className="rounded-xl border border-benell-stroke bg-benell-surface p-3">
                          <p className="text-body font-semibold">{task.title}</p>
                          <p className="text-label mt-1 text-benell-text-soft">
                            Proyecto: {initiatives.find((initiative) => initiative.id === task.initiativeId)?.name ?? "Sin proyecto"}
                          </p>
                          <p className="text-label text-benell-text-soft">Responsable: {employeesById[task.assigneeId]?.name ?? "Sin asignar"}</p>
                          <p className="text-label text-benell-text-soft">Compromiso: {formatDate(task.dueDate)}</p>

                          {canEditTask ? (
                            <div className="mt-2 grid gap-2">
                              <select
                                value={draft.status}
                                onChange={(event) =>
                                  setTaskDrafts((prev) => ({
                                    ...prev,
                                    [task.id]: {
                                      ...draft,
                                      status: event.target.value as TaskStatus,
                                    },
                                  }))
                                }
                                className="text-body rounded-xl border border-benell-stroke bg-white px-3 py-2"
                              >
                                {TASK_COLUMNS.map((status) => (
                                  <option key={status} value={status}>
                                    {TASK_STATUS_LABELS[status]}
                                  </option>
                                ))}
                              </select>

                              <input
                                value={draft.dueDateRequest}
                                onChange={(event) =>
                                  setTaskDrafts((prev) => ({
                                    ...prev,
                                    [task.id]: {
                                      ...draft,
                                      dueDateRequest: event.target.value,
                                    },
                                  }))
                                }
                                placeholder="Solicitud ajuste fecha (YYYY-MM-DD)"
                                className="text-body rounded-xl border border-benell-stroke bg-white px-3 py-2"
                              />

                              <textarea
                                value={draft.blockerNote}
                                onChange={(event) =>
                                  setTaskDrafts((prev) => ({
                                    ...prev,
                                    [task.id]: {
                                      ...draft,
                                      blockerNote: event.target.value,
                                    },
                                  }))
                                }
                                rows={2}
                                placeholder="Nota de bloqueo"
                                className="text-body rounded-xl border border-benell-stroke bg-white px-3 py-2"
                              />

                              <input
                                value={draft.evidenceUrl}
                                onChange={(event) =>
                                  setTaskDrafts((prev) => ({
                                    ...prev,
                                    [task.id]: {
                                      ...draft,
                                      evidenceUrl: event.target.value,
                                    },
                                  }))
                                }
                                placeholder="URL evidencia"
                                className="text-body rounded-xl border border-benell-stroke bg-white px-3 py-2"
                              />

                              <button
                                type="button"
                                onClick={() => handleTaskBoardSubmit(task)}
                                className="rounded-pill bg-benell-brown px-3 py-2 text-label font-semibold text-white"
                              >
                                Guardar actualización
                              </button>
                            </div>
                          ) : null}
                        </div>
                      );
                    })}
                    {items.length === 0 ? <p className="text-label text-benell-text-soft">Sin tareas en esta columna.</p> : null}
                  </div>
                </article>
              );
            })}
          </div>
        </section>
      </div>

      <div className="grid gap-5 xl:grid-cols-2">
        <div className="space-y-2">
          {meetingsError ? <p className="text-label text-benell-red">{meetingsError}</p> : null}
          <MeetingsWidget
            meetings={meetings}
            role={normalizedRole}
            participantOptions={participantOptions}
            isSaving={isSavingMeeting}
            departmentLabel="Projects"
            leadTitle="Lider de Proyectos"
            onRequestMeeting={handleRequestMeeting}
            onScheduleMeeting={handleScheduleMeeting}
            onCompleteMeeting={handleCompleteMeeting}
          />
        </div>

        <EmployeePerformanceTable
          employees={employees}
          initiatives={filteredInitiatives}
          tasks={filteredTasks}
          role={normalizedRole}
          currentEmployeeId={session?.user?.id}
        />
      </div>

      {selectedInitiative ? (
        <section className="rounded-benell border border-benell-stroke bg-benell-surface p-5 shadow-benell">
          <h2 className="text-h2 font-semibold">Detalle seleccionado</h2>
          <div className="mt-3 grid gap-4 xl:grid-cols-3">
            <article className="rounded-xl border border-benell-stroke bg-white p-3">
              <h3 className="text-body font-semibold">Overview</h3>
              <p className="text-label mt-1 text-benell-text-soft">Nombre: {selectedInitiative.name}</p>
              <p className="text-label text-benell-text-soft">Tipo: {INITIATIVE_TYPE_LABELS[selectedInitiative.type]}</p>
              <p className="text-label text-benell-text-soft">Líder: {employeesById[selectedInitiative.ownerId]?.name ?? "Sin líder"}</p>
              <p className="text-label text-benell-text-soft">Due date: {formatDate(selectedInitiative.dueDate)}</p>
              <p className="text-label text-benell-text-soft">Etapa: {PROJECT_STAGE_LABELS[selectedInitiative.status]}</p>
            </article>

            <article className="rounded-xl border border-benell-stroke bg-white p-3">
              <h3 className="text-body font-semibold">Finanzas</h3>
              <p className="text-label mt-1 text-benell-text-soft">Revenue planeado: {formatCurrency(plannedRevenue(selectedInitiative))}</p>
              <p className="text-label text-benell-text-soft">Revenue actual: {formatCurrency(actualRevenue(selectedInitiative))}</p>
              <p className="text-label text-benell-text-soft">Costo planeado: {formatCurrency(plannedCost(selectedInitiative))}</p>
              <p className="text-label text-benell-text-soft">Costo actual: {formatCurrency(actualCost(selectedInitiative))}</p>
              <p className={cn("text-label font-semibold", costVariancePct(selectedInitiative) > 0 ? "text-benell-red" : "text-benell-green")}>
                Variación de costo: {costVariancePct(selectedInitiative).toFixed(1)}%
              </p>
              <p className={cn("text-label font-semibold", actualProfit(selectedInitiative) >= 0 ? "text-benell-green" : "text-benell-red")}>
                Utilidad / margen: {formatCurrency(actualProfit(selectedInitiative))} · {actualMarginPct(selectedInitiative).toFixed(1)}%
              </p>
              <p className="text-label text-benell-text-soft">Salud promedio: {average(Object.values(initiativeScoresById)).toFixed(1)}</p>
            </article>

            <article className="rounded-xl border border-benell-stroke bg-white p-3">
              <h3 className="text-body font-semibold">Timeline</h3>
              <ul className="mt-2 space-y-2">
                {selectedTimeline.length > 0 ? (
                  selectedTimeline.map((item, index) => (
                    <li key={`${item.at}-${index}`} className="text-label text-benell-text-soft">
                      {formatDate(item.at)} · {item.label}
                    </li>
                  ))
                ) : (
                  <li className="text-label text-benell-text-soft">Sin actividad reciente registrada.</li>
                )}
              </ul>
            </article>
          </div>
        </section>
      ) : null}

      {saveActivityCards.length > 0 ? (
        <div className="fixed right-5 top-24 z-[65] w-[min(90vw,360px)] space-y-2">
          {saveActivityCards.map((card) => (
            <article key={card.id} className="rounded-xl border border-benell-stroke bg-white px-4 py-3 shadow-benell">
              <p className="text-label font-semibold text-benell-green">{card.title}</p>
              <p className="text-label mt-1 text-benell-text-soft">{card.detail}</p>
            </article>
          ))}
        </div>
      ) : null}

      <InitiativeDrawer
        mode="projects"
        initiative={selectedInitiative}
        tasksById={tasksById}
        employeesById={employeesById}
        locationsById={locationsById}
        role={normalizedRole}
        currentEmployeeId={session?.user?.id}
        isOpen={Boolean(selectedInitiative)}
        onClose={() => setSelectedInitiativeId(null)}
        onSaveInitiative={handleSaveInitiative}
        onDeleteInitiative={canManage ? handleDeleteInitiative : undefined}
        isDeletingInitiative={selectedInitiativeId ? deletingInitiativeId === selectedInitiativeId : false}
        onUpdateTask={handleUpdateTask}
        onCreateTask={handleCreateTask}
        onCreateMilestone={handleCreateMilestone}
        onUpdateMilestone={handleUpdateMilestone}
        onAddMilestoneCheckpoint={handleAddMilestoneCheckpoint}
      />
    </div>
  );
}
