import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
import {
  CalendarDays,
  ChevronLeft,
  ChevronRight,
  Clock3,
  ListChecks,
  Loader2,
  MapPin,
  Pencil,
  Plus,
  RefreshCw,
  Trash2,
  UserRound,
} from "lucide-react";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { Badge } from "@/components/ui/badge";
import { SearchableSelect } from "./SearchableSelect";
import { useAppLists } from "@/lib/appLists";
import { dedupeOptions, normalizeOptionKey } from "@/lib/optionUtils";
import {
  addProjectTimeEntry,
  deleteProjectTimeEntry,
  loadProjectTimeEntries,
  updateProjectTimeEntry,
  type Project,
  type ProjectTimeEntry,
} from "@/lib/store";
import { cn } from "@/lib/utils";
import { syncProjectTimeToSheet } from "@/lib/timeSheetSync";
import { toast } from "sonner";

interface ProjectTimeDialogProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  project: Project | null;
}

type BreakdownRow = {
  key: string;
  label: string;
  minutes: number;
};

const ENTRIES_PER_PAGE = 10;

function todayLocal() {
  const now = new Date();
  const offset = now.getTimezoneOffset() * 60_000;
  return new Date(now.getTime() - offset).toISOString().slice(0, 10);
}

function splitProjectCountries(value: string) {
  return dedupeOptions(
    String(value || "")
      .split(",")
      .map((item) => item.trim())
      .filter(Boolean),
  );
}

function formatDuration(totalMinutes: number, compact = false) {
  const safeMinutes = Math.max(0, Math.round(Number(totalMinutes || 0)));
  const hours = Math.floor(safeMinutes / 60);
  const minutes = safeMinutes % 60;

  if (compact) {
    if (hours && minutes) return `${hours} h ${minutes} min`;
    if (hours) return `${hours} h`;
    return `${minutes} min`;
  }

  if (hours && minutes) return `${hours} ${hours === 1 ? "hora" : "horas"} ${minutes} min`;
  if (hours) return `${hours} ${hours === 1 ? "hora" : "horas"}`;
  return `${minutes} min`;
}

function formatWorkDate(value: string) {
  if (!value) return "—";
  const date = new Date(`${value}T12:00:00`);
  if (!Number.isFinite(date.getTime())) return value;

  return new Intl.DateTimeFormat("es-DO", {
    day: "2-digit",
    month: "short",
    year: "numeric",
  }).format(date);
}

function formatCreatedAt(timestamp: number) {
  return new Intl.DateTimeFormat("es-DO", {
    day: "2-digit",
    month: "short",
    hour: "numeric",
    minute: "2-digit",
  }).format(new Date(timestamp));
}

function buildBreakdown(
  entries: ProjectTimeEntry[],
  selector: (entry: ProjectTimeEntry) => string,
): BreakdownRow[] {
  const groups = new Map<string, BreakdownRow>();

  for (const entry of entries) {
    const label = selector(entry).trim() || "Sin especificar";
    const key = normalizeOptionKey(label) || label.toLowerCase();
    const current = groups.get(key);

    if (current) {
      current.minutes += entry.durationMinutes;
    } else {
      groups.set(key, { key, label, minutes: entry.durationMinutes });
    }
  }

  return [...groups.values()].sort(
    (a, b) => b.minutes - a.minutes || a.label.localeCompare(b.label, "es"),
  );
}

function isMissingTimeTableError(error: unknown) {
  const message = error instanceof Error ? error.message : String(error || "");
  const normalized = message.toLowerCase();

  return (
    normalized.includes("tablero_cdc_project_time_entries") ||
    normalized.includes("relation") ||
    normalized.includes("schema cache")
  );
}

export function ProjectTimeDialog({ open, onOpenChange, project }: ProjectTimeDialogProps) {
  const { lists } = useAppLists();
  const [entries, setEntries] = useState<ProjectTimeEntry[]>([]);
  const [entriesProjectId, setEntriesProjectId] = useState<string | null>(null);
  const loadRequestRef = useRef(0);
  const [loading, setLoading] = useState(false);
  const [saving, setSaving] = useState(false);
  const [deletingId, setDeletingId] = useState<string | null>(null);
  const [editingId, setEditingId] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [sheetSyncWarning, setSheetSyncWarning] = useState<string | null>(null);
  const [country, setCountry] = useState("");
  const [taskName, setTaskName] = useState("");
  const [hours, setHours] = useState("");
  const [minutes, setMinutes] = useState("");
  const [workDate, setWorkDate] = useState(todayLocal());
  const [notes, setNotes] = useState("");
  const [page, setPage] = useState(1);

  const projectCountries = useMemo(
    () => splitProjectCountries(project?.bu || ""),
    [project?.bu],
  );
  const countryOptions = useMemo(
    () => dedupeOptions([...projectCountries, ...lists.bus, country]),
    [country, lists.bus, projectCountries],
  );

  // Nunca mostramos registros cargados para un proyecto distinto al que está abierto.
  // Esto evita el destello de datos del proyecto anterior mientras llega la nueva consulta.
  const projectEntries = entriesProjectId === project?.id ? entries : [];

  const totalMinutes = useMemo(
    () => projectEntries.reduce((sum, entry) => sum + entry.durationMinutes, 0),
    [projectEntries],
  );
  const countryBreakdown = useMemo(
    () => buildBreakdown(projectEntries, (entry) => entry.country),
    [projectEntries],
  );
  const taskBreakdown = useMemo(
    () => buildBreakdown(projectEntries, (entry) => entry.taskName),
    [projectEntries],
  );
  const recentTasks = useMemo(
    () => dedupeOptions(projectEntries.map((entry) => entry.taskName)).slice(0, 8),
    [projectEntries],
  );

  const totalPages = Math.max(1, Math.ceil(projectEntries.length / ENTRIES_PER_PAGE));
  const safePage = Math.min(page, totalPages);
  const pageStart = (safePage - 1) * ENTRIES_PER_PAGE;
  const visibleEntries = projectEntries.slice(pageStart, pageStart + ENTRIES_PER_PAGE);
  const visibleStart = projectEntries.length === 0 ? 0 : pageStart + 1;
  const visibleEnd = Math.min(pageStart + ENTRIES_PER_PAGE, projectEntries.length);

  const loadEntries = useCallback(async () => {
    const projectId = project?.id;
    if (!projectId) return;

    const requestId = ++loadRequestRef.current;

    try {
      setLoading(true);
      setError(null);
      const rows = await loadProjectTimeEntries(projectId);
      if (requestId !== loadRequestRef.current) return;

      setEntries(rows);
      setEntriesProjectId(projectId);

      // Reconciliación silenciosa: al abrir Tiempo se vuelve a comprobar Excel.
      void syncProjectTimeToSheet(projectId)
        .then(() => {
          if (requestId === loadRequestRef.current) setSheetSyncWarning(null);
        })
        .catch((syncError) => {
          console.warn("No se pudo reconciliar el registro de horas con Excel:", syncError);
        });
    } catch (loadError) {
      if (requestId !== loadRequestRef.current) return;
      console.error("No se pudo cargar el tiempo del proyecto:", loadError);
      setEntries([]);
      setEntriesProjectId(projectId);
      setError(
        isMissingTimeTableError(loadError)
          ? "El módulo de tiempo todavía no está instalado en Supabase. Ejecuta supabase_project_time_entries.sql."
          : loadError instanceof Error
            ? loadError.message
            : "No se pudo cargar el desglose de tiempo.",
      );
    } finally {
      if (requestId === loadRequestRef.current) setLoading(false);
    }
  }, [project?.id]);

  useEffect(() => {
    if (!open || !project?.id) return;

    // Invalidar cualquier carga anterior antes de solicitar el nuevo proyecto.
    loadRequestRef.current += 1;
    setEntriesProjectId(null);
    setEntries([]);
    setLoading(true);
    setCountry(projectCountries[0] || "");
    setTaskName("");
    setHours("");
    setMinutes("");
    setWorkDate(todayLocal());
    setNotes("");
    setSheetSyncWarning(null);
    setEditingId(null);
    setPage(1);
    void loadEntries();
  }, [loadEntries, open, project?.id, projectCountries]);

  useEffect(() => {
    if (page > totalPages) setPage(totalPages);
  }, [page, totalPages]);

  const durationMinutes =
    Math.max(0, Math.floor(Number(hours || 0))) * 60 +
    Math.max(0, Math.floor(Number(minutes || 0)));
  const validDuration = Number.isFinite(durationMinutes) && durationMinutes > 0;
  const canSubmit = Boolean(country.trim() && taskName.trim() && workDate && validDuration);
  const isEditing = Boolean(editingId);

  const resetForm = () => {
    setCountry(projectCountries[0] || "");
    setTaskName("");
    setHours("");
    setMinutes("");
    setWorkDate(todayLocal());
    setNotes("");
    setEditingId(null);
  };

  const handleEdit = (entry: ProjectTimeEntry) => {
    const safeMinutes = Math.max(0, Math.round(entry.durationMinutes));
    setEditingId(entry.id);
    setCountry(entry.country);
    setTaskName(entry.taskName);
    setHours(String(Math.floor(safeMinutes / 60)));
    setMinutes(String(safeMinutes % 60));
    setWorkDate(entry.workDate);
    setNotes(entry.notes || "");
    setError(null);
    requestAnimationFrame(() => {
      document.querySelector('[data-project-time-form="true"]')?.scrollIntoView({
        behavior: "smooth",
        block: "start",
      });
    });
  };

  const handleAdd = async () => {
    if (!project?.id || !canSubmit || saving) return;

    try {
      setSaving(true);
      setError(null);
      const payload = { country, taskName, durationMinutes, workDate, notes };
      const saved = editingId
        ? await updateProjectTimeEntry(editingId, payload)
        : await addProjectTimeEntry(project.id, payload);

      if (editingId) {
        setEntries((current) =>
          current
            .map((item) => (item.id === saved.id ? saved : item))
            .sort((a, b) => b.workDate.localeCompare(a.workDate) || b.createdAt - a.createdAt),
        );
      } else {
        setEntries((current) => [saved, ...current]);
        setPage(1);
      }
      resetForm();
      toast.success(editingId ? "Registro de tiempo actualizado" : "Tiempo registrado", {
        description: `${formatDuration(saved.durationMinutes, true)} · ${saved.country} · ${saved.taskName}`,
      });

      try {
        await syncProjectTimeToSheet(project.id);
        setSheetSyncWarning(null);
      } catch (syncError) {
        console.warn("El tiempo se guardó, pero Excel no pudo sincronizarse todavía:", syncError);
        setSheetSyncWarning(
          "El tiempo quedó guardado en el Tablero, pero el Excel no pudo actualizarse ahora. Se reintentará automáticamente al volver a abrir Tiempo.",
        );
        toast.warning("Tiempo guardado; Excel pendiente", {
          description: "La app volverá a intentar la sincronización automáticamente.",
        });
      }
    } catch (saveError) {
      console.error("No se pudo registrar el tiempo:", saveError);
      const message = isMissingTimeTableError(saveError)
        ? "Ejecuta supabase_project_time_entries.sql en Supabase antes de usar este módulo."
        : saveError instanceof Error
          ? saveError.message
          : "No se pudo registrar el tiempo.";
      setError(message);
      toast.error("No se pudo registrar el tiempo", { description: message });
    } finally {
      setSaving(false);
    }
  };

  const handleDelete = async (entry: ProjectTimeEntry) => {
    const confirmed = window.confirm(
      `¿Eliminar este registro de ${formatDuration(entry.durationMinutes, true)} para “${entry.taskName}”?`,
    );

    if (!confirmed) return;

    try {
      setDeletingId(entry.id);
      await deleteProjectTimeEntry(entry.id);
      setEntries((current) => current.filter((item) => item.id !== entry.id));
      if (editingId === entry.id) resetForm();
      toast.success("Registro de tiempo eliminado");

      if (project?.id) {
        try {
          await syncProjectTimeToSheet(project.id);
          setSheetSyncWarning(null);
        } catch (syncError) {
          console.warn("El registro se eliminó, pero Excel no pudo sincronizarse todavía:", syncError);
          setSheetSyncWarning(
            "El registro se eliminó del Tablero, pero el Excel no pudo actualizarse ahora. Se reintentará automáticamente al volver a abrir Tiempo.",
          );
          toast.warning("Registro eliminado; Excel pendiente", {
            description: "La app volverá a intentar la sincronización automáticamente.",
          });
        }
      }
    } catch (deleteError) {
      console.error("No se pudo eliminar el registro de tiempo:", deleteError);
      toast.error("No se pudo eliminar", {
        description:
          deleteError instanceof Error ? deleteError.message : "Intenta nuevamente.",
      });
    } finally {
      setDeletingId(null);
    }
  };

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-h-[92vh] max-w-5xl overflow-y-auto p-0 gap-0">
        <div className="border-b border-border bg-muted/20 px-6 py-5 sm:px-7">
          <DialogHeader>
            <div className="flex items-start gap-3">
              <span className="mt-0.5 flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-2xl bg-primary/10 text-primary">
                <Clock3 className="h-5 w-5" />
              </span>
              <div className="min-w-0">
                <DialogTitle className="text-xl tracking-tight">Tiempo dedicado</DialogTitle>
                <DialogDescription className="mt-1">
                  Desglose por país y tarea para <span className="font-medium text-foreground">{project?.nombre || "este proyecto"}</span>.
                </DialogDescription>
              </div>
            </div>
          </DialogHeader>
        </div>

        <div className="space-y-6 px-6 py-6 sm:px-7">
          <div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
            <SummaryCard
              icon={<Clock3 className="h-4 w-4" />}
              label="Total dedicado"
              value={formatDuration(totalMinutes, true)}
            />
            <SummaryCard
              icon={<MapPin className="h-4 w-4" />}
              label="Países con tiempo"
              value={String(countryBreakdown.length)}
            />
            <SummaryCard
              icon={<ListChecks className="h-4 w-4" />}
              label="Tareas registradas"
              value={String(taskBreakdown.length)}
            />
          </div>

          <section data-project-time-form="true" className="rounded-2xl border border-border bg-card p-4 sm:p-5">
            <div className="mb-4 flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between">
              <div>
                <h3 className="text-sm font-semibold">{isEditing ? "Editar tiempo" : "Agregar tiempo"}</h3>
                <p className="mt-0.5 text-xs text-muted-foreground">
                  {isEditing
                    ? "Modifica los datos del registro seleccionado y guarda los cambios."
                    : "Cada registro queda asociado a este proyecto y al usuario que lo agrega."}
                </p>
              </div>
              <Button
                type="button"
                variant="ghost"
                size="sm"
                className="h-8 self-start rounded-full px-2.5 text-xs text-muted-foreground"
                onClick={() => void loadEntries()}
                disabled={loading}
              >
                {loading ? (
                  <Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" />
                ) : (
                  <RefreshCw className="mr-1.5 h-3.5 w-3.5" />
                )}
                Actualizar
              </Button>
            </div>

            <div className="grid grid-cols-1 gap-4 md:grid-cols-12">
              <div className="space-y-1.5 md:col-span-4">
                <Label>País</Label>
                <SearchableSelect
                  value={country}
                  options={countryOptions}
                  onValueChange={setCountry}
                  placeholder="Seleccionar país…"
                  searchPlaceholder="Buscar país…"
                  emptyText="No se encontró ese país."
                />
              </div>

              <div className="space-y-1.5 md:col-span-4">
                <Label>Tarea</Label>
                <Input
                  value={taskName}
                  onChange={(event) => setTaskName(event.target.value)}
                  placeholder="Ej: Diseño, adaptación, reunión…"
                  className="h-10"
                  maxLength={160}
                />
              </div>

              <div className="space-y-1.5 md:col-span-2">
                <Label>Horas</Label>
                <Input
                  type="number"
                  min={0}
                  step={1}
                  inputMode="numeric"
                  value={hours}
                  onChange={(event) => setHours(event.target.value)}
                  placeholder="0"
                  className="h-10"
                />
              </div>

              <div className="space-y-1.5 md:col-span-2">
                <Label>Minutos</Label>
                <Input
                  type="number"
                  min={0}
                  max={59}
                  step={1}
                  inputMode="numeric"
                  value={minutes}
                  onChange={(event) => {
                    const value = event.target.value;
                    if (value === "") {
                      setMinutes("");
                      return;
                    }
                    setMinutes(String(Math.min(59, Math.max(0, Math.floor(Number(value) || 0)))));
                  }}
                  placeholder="0"
                  className="h-10"
                />
              </div>

              <div className="space-y-1.5 md:col-span-4">
                <Label>Fecha</Label>
                <Input
                  type="date"
                  value={workDate}
                  onChange={(event) => setWorkDate(event.target.value)}
                  className="h-10"
                />
              </div>

              <div className="space-y-1.5 md:col-span-8">
                <Label>Nota <span className="font-normal text-muted-foreground">(opcional)</span></Label>
                <Textarea
                  value={notes}
                  onChange={(event) => setNotes(event.target.value)}
                  placeholder="Detalle breve de lo realizado…"
                  rows={2}
                  maxLength={600}
                  className="min-h-[64px] resize-none"
                />
              </div>
            </div>

            {recentTasks.length > 0 && (
              <div className="mt-3 flex flex-wrap items-center gap-1.5">
                <span className="mr-1 text-[11px] text-muted-foreground">Tareas recientes:</span>
                {recentTasks.map((task) => (
                  <button
                    type="button"
                    key={task}
                    onClick={() => setTaskName(task)}
                    className="rounded-full border border-border bg-muted/30 px-2.5 py-1 text-[11px] text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
                  >
                    {task}
                  </button>
                ))}
              </div>
            )}

            <div className="mt-4 flex flex-col gap-2 border-t border-border/70 pt-4 sm:flex-row sm:items-center sm:justify-between">
              <p className="text-xs text-muted-foreground">
                Duración a registrar: <span className="font-semibold text-foreground">{formatDuration(durationMinutes, true)}</span>
              </p>
              <div className="flex flex-wrap items-center justify-end gap-2">
                {isEditing && (
                  <Button
                    type="button"
                    variant="outline"
                    onClick={resetForm}
                    disabled={saving}
                    className="rounded-full"
                  >
                    Cancelar
                  </Button>
                )}
                <Button
                  type="button"
                  onClick={() => void handleAdd()}
                  disabled={!canSubmit || saving || loading}
                  className="gap-1.5 rounded-full"
                >
                  {saving ? (
                    <Loader2 className="h-4 w-4 animate-spin" />
                  ) : isEditing ? (
                    <Pencil className="h-4 w-4" />
                  ) : (
                    <Plus className="h-4 w-4" />
                  )}
                  {saving ? "Guardando…" : isEditing ? "Guardar cambios" : "Agregar registro"}
                </Button>
              </div>
            </div>

            {sheetSyncWarning && (
              <div className="mt-4 rounded-xl border border-amber-300/60 bg-amber-50 px-3 py-2 text-xs text-amber-800">
                {sheetSyncWarning}
              </div>
            )}

            {error && (
              <div className="mt-4 rounded-xl border border-destructive/20 bg-destructive/5 px-3 py-2 text-xs text-destructive">
                {error}
              </div>
            )}
          </section>

          <div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
            <BreakdownCard
              icon={<MapPin className="h-4 w-4" />}
              title="Desglose por país"
              rows={countryBreakdown}
              totalMinutes={totalMinutes}
              emptyText="Aún no hay países con tiempo registrado."
            />
            <BreakdownCard
              icon={<ListChecks className="h-4 w-4" />}
              title="Desglose por tarea"
              rows={taskBreakdown}
              totalMinutes={totalMinutes}
              emptyText="Aún no hay tareas con tiempo registrado."
            />
          </div>

          <section className="overflow-hidden rounded-2xl border border-border bg-card">
            <div className="flex flex-col gap-2 border-b border-border bg-muted/20 px-4 py-3 sm:flex-row sm:items-center sm:justify-between">
              <div>
                <h3 className="text-sm font-semibold">Registros detallados</h3>
                <p className="text-xs text-muted-foreground">
                  {projectEntries.length === 0
                    ? "Sin registros todavía."
                    : `Mostrando ${visibleStart}-${visibleEnd} de ${projectEntries.length}.`}
                </p>
              </div>
              {projectEntries.length > ENTRIES_PER_PAGE && (
                <span className="text-xs text-muted-foreground">
                  Página {safePage} de {totalPages}
                </span>
              )}
            </div>

            {loading && projectEntries.length === 0 ? (
              <div className="flex items-center justify-center gap-2 px-4 py-12 text-sm text-muted-foreground">
                <Loader2 className="h-4 w-4 animate-spin" />
                Cargando tiempo…
              </div>
            ) : projectEntries.length === 0 ? (
              <div className="px-4 py-10 text-center">
                <Clock3 className="mx-auto h-8 w-8 text-muted-foreground/40" />
                <p className="mt-2 text-sm font-medium">Aún no hay tiempo registrado</p>
                <p className="mt-1 text-xs text-muted-foreground">
                  Agrega el primer registro usando el formulario de arriba.
                </p>
              </div>
            ) : (
              <div className="divide-y divide-border/70">
                {visibleEntries.map((entry) => (
                  <TimeEntryRow
                    key={entry.id}
                    entry={entry}
                    deleting={deletingId === entry.id}
                    editing={editingId === entry.id}
                    onEdit={() => handleEdit(entry)}
                    onDelete={() => void handleDelete(entry)}
                  />
                ))}
              </div>
            )}

            {projectEntries.length > ENTRIES_PER_PAGE && (
              <div className="flex items-center justify-between border-t border-border bg-muted/10 px-4 py-3">
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  className="h-8 gap-1 rounded-full"
                  disabled={safePage <= 1}
                  onClick={() => setPage((current) => Math.max(1, current - 1))}
                >
                  <ChevronLeft className="h-3.5 w-3.5" />
                  Anterior
                </Button>
                <span className="text-xs text-muted-foreground">
                  {safePage} / {totalPages}
                </span>
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  className="h-8 gap-1 rounded-full"
                  disabled={safePage >= totalPages}
                  onClick={() => setPage((current) => Math.min(totalPages, current + 1))}
                >
                  Siguiente
                  <ChevronRight className="h-3.5 w-3.5" />
                </Button>
              </div>
            )}
          </section>
        </div>
      </DialogContent>
    </Dialog>
  );
}

function SummaryCard({
  icon,
  label,
  value,
}: {
  icon: ReactNode;
  label: string;
  value: string;
}) {
  return (
    <div className="flex items-center gap-3 rounded-2xl border border-border bg-card px-4 py-3.5 shadow-sm">
      <span className="flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary">
        {icon}
      </span>
      <div className="min-w-0">
        <p className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">{label}</p>
        <p className="mt-0.5 truncate text-lg font-semibold tabular-nums text-foreground">{value}</p>
      </div>
    </div>
  );
}

function BreakdownCard({
  icon,
  title,
  rows,
  totalMinutes,
  emptyText,
}: {
  icon: ReactNode;
  title: string;
  rows: BreakdownRow[];
  totalMinutes: number;
  emptyText: string;
}) {
  return (
    <section className="rounded-2xl border border-border bg-card p-4">
      <div className="mb-3 flex items-center gap-2">
        <span className="text-primary">{icon}</span>
        <h3 className="text-sm font-semibold">{title}</h3>
      </div>

      {rows.length === 0 ? (
        <p className="rounded-xl border border-dashed border-border bg-muted/20 px-3 py-5 text-center text-xs text-muted-foreground">
          {emptyText}
        </p>
      ) : (
        <div className="space-y-3">
          {rows.map((row) => {
            const percentage = totalMinutes > 0 ? (row.minutes / totalMinutes) * 100 : 0;
            return (
              <div key={row.key}>
                <div className="mb-1 flex items-center justify-between gap-3 text-xs">
                  <span className="min-w-0 truncate font-medium text-foreground" title={row.label}>
                    {row.label}
                  </span>
                  <span className="flex-shrink-0 font-semibold tabular-nums text-foreground">
                    {formatDuration(row.minutes, true)}
                  </span>
                </div>
                <div className="h-1.5 overflow-hidden rounded-full bg-muted">
                  <div
                    className="h-full rounded-full bg-primary/70 transition-[width]"
                    style={{ width: `${Math.max(2, Math.min(100, percentage))}%` }}
                  />
                </div>
              </div>
            );
          })}
        </div>
      )}
    </section>
  );
}

function TimeEntryRow({
  entry,
  deleting,
  editing,
  onEdit,
  onDelete,
}: {
  entry: ProjectTimeEntry;
  deleting: boolean;
  editing: boolean;
  onEdit: () => void;
  onDelete: () => void;
}) {
  return (
    <div className="grid grid-cols-1 gap-3 px-4 py-4 sm:grid-cols-[minmax(0,1fr)_auto] sm:items-start">
      <div className="min-w-0">
        <div className="flex flex-wrap items-center gap-2">
          <span className="font-medium text-sm text-foreground">{entry.taskName}</span>
          <Badge variant="secondary" className="h-5 px-1.5 text-[10px] font-normal">
            {entry.country}
          </Badge>
          <span className="rounded-full bg-primary/10 px-2 py-0.5 text-xs font-semibold tabular-nums text-primary">
            {formatDuration(entry.durationMinutes, true)}
          </span>
        </div>

        {entry.notes && (
          <p className="mt-1.5 whitespace-pre-wrap text-xs leading-relaxed text-muted-foreground">
            {entry.notes}
          </p>
        )}

        <div className="mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-[11px] text-muted-foreground">
          <span className="inline-flex items-center gap-1">
            <CalendarDays className="h-3 w-3" />
            {formatWorkDate(entry.workDate)}
          </span>
          <span className="inline-flex items-center gap-1" title={entry.actorEmail || entry.actorName}>
            <UserRound className="h-3 w-3" />
            {entry.actorName}
          </span>
          <span>Registrado {formatCreatedAt(entry.createdAt)}</span>
        </div>
      </div>

      <div className="flex items-center justify-self-end gap-1">
        <Button
          type="button"
          variant="ghost"
          size="icon"
          onClick={onEdit}
          disabled={deleting}
          className={cn(
            "h-8 w-8 rounded-full text-muted-foreground hover:bg-primary/10 hover:text-primary",
            editing && "bg-primary/10 text-primary",
          )}
          title="Editar registro"
        >
          <Pencil className="h-4 w-4" />
        </Button>
        <Button
          type="button"
          variant="ghost"
          size="icon"
          onClick={onDelete}
          disabled={deleting}
          className={cn(
            "h-8 w-8 rounded-full text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
            deleting && "text-destructive",
          )}
          title="Eliminar registro"
        >
          {deleting ? <Loader2 className="h-4 w-4 animate-spin" /> : <Trash2 className="h-4 w-4" />}
        </Button>
      </div>
    </div>
  );
}
