import { AppLayout } from "@/components/AppLayout";
import { Input } from "@/components/ui/input";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Building2, FileText, Users, Clock, Package, ClipboardList, CreditCard, Wrench, Camera, Loader2, AlertTriangle, Car, Heart, Cake, PenLine, CalendarIcon, CalendarDays, Eye, EyeOff, Banknote, ChevronDown, ChevronUp, Search, Home } from "lucide-react";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { useLocation, useNavigate } from "react-router-dom";
import { useAuth } from "@/contexts/AuthContext";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { supabase } from "@/integrations/supabase/client";
import { useEffect, useState, useCallback, useMemo, lazy, Suspense } from "react";
import { useIsMobile } from "@/hooks/use-mobile";
const CompanySettingsEditor = lazy(() => import("@/components/CompanySettingsEditor").then(m => ({ default: m.CompanySettingsEditor })));
// Componentes leves: import direto
import { NinkuAlert } from "@/components/dashboard/NinkuAlert";
import { PendingPanel } from "@/components/dashboard/PendingPanel";
import { MonthlyTargetBar } from "@/components/dashboard/MonthlyTargetBar";
// Componentes pesados (Recharts, Leaflet, calendários, listas grandes): lazy-load
const MonthlyZairyoSummary = lazy(() => import("@/components/dashboard/MonthlyZairyoSummary").then(m => ({ default: m.MonthlyZairyoSummary })));
const GenbaProfitSummary = lazy(() => import("@/components/dashboard/GenbaProfitSummary").then(m => ({ default: m.GenbaProfitSummary })));
const GenbaProfitChart = lazy(() => import("@/components/dashboard/GenbaProfitChart").then(m => ({ default: m.GenbaProfitChart })));
const MonthlyFinanceSummary = lazy(() => import("@/components/dashboard/MonthlyFinanceSummary").then(m => ({ default: m.MonthlyFinanceSummary })));
const OldAppVersionsPanel = lazy(() => import("@/components/dashboard/OldAppVersionsPanel").then(m => ({ default: m.OldAppVersionsPanel })));
const EmployeeRanking = lazy(() => import("@/components/dashboard/EmployeeRanking").then(m => ({ default: m.EmployeeRanking })));
const UnifiedCalendar = lazy(() => import("@/components/dashboard/UnifiedCalendar").then(m => ({ default: m.UnifiedCalendar })));
const LivePresence = lazy(() => import("@/components/dashboard/LivePresence").then(m => ({ default: m.LivePresence })));
const LiveGpsMap = lazy(() => import("@/components/dashboard/LiveGpsMap").then(m => ({ default: m.LiveGpsMap })));
const BirthdayPanel = lazy(() => import("@/components/dashboard/BirthdayPanel").then(m => ({ default: m.BirthdayPanel })));
const RecentDrawingActivity = lazy(() => import("@/components/dashboard/RecentDrawingActivity").then(m => ({ default: m.RecentDrawingActivity })));
const ShikudaiScorePanel = lazy(() => import("@/components/dashboard/ShikudaiScorePanel").then(m => ({ default: m.ShikudaiScorePanel })));
// generateMonthlyReportPdf é carregado sob demanda (jspdf é pesado)
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Calendar } from "@/components/ui/calendar";
import { toast } from "sonner";
import { sendApprovalNotification } from "@/lib/approval-notifications";
import { differenceInDays, parseISO, format, addYears } from "date-fns";
import { cn } from "@/lib/utils";
import { useEmployeePermission } from "@/hooks/use-employee-permission";

// Wrapper para widgets lazy: placeholder discreto que mantém altura aproximada
const WidgetFallback = ({ minHeight = 120 }: { minHeight?: number }) => (
  <div
    className="flex items-center justify-center rounded-md border bg-muted/30"
    style={{ minHeight }}
  >
    <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
  </div>
);
const LazyWidget = ({ children, minHeight }: { children: React.ReactNode; minHeight?: number }) => (
  <Suspense fallback={<WidgetFallback minHeight={minHeight} />}>{children}</Suspense>
);

const SectionToggleButton = ({ collapsed, onToggle, sectionKey }: { collapsed: boolean; onToggle: (key: string) => void; sectionKey: string }) => (
  <Button variant="ghost" size="sm" className="h-6 w-6 p-0 shrink-0" onClick={(e) => { e.stopPropagation(); onToggle(sectionKey); }}>
    {collapsed ? <ChevronDown className="w-4 h-4" /> : <ChevronUp className="w-4 h-4" />}
  </Button>
);

const quickLinks = [
  { title: "現場管理", desc: "工事・現場の一覧管理", icon: Building2, url: "/genba", color: "bg-primary" },
  { title: "請求書", desc: "請求書の作成・管理", icon: FileText, url: "/seikyu", color: "bg-success" },
  { title: "注文書", desc: "注文書の作成・管理", icon: ClipboardList, url: "/chumon", color: "bg-warning" },
  { title: "社員マスタ", desc: "従業員情報の管理", icon: Users, url: "/shain", color: "bg-accent" },
  { title: "タイムカード", desc: "出退勤の記録", icon: Clock, url: "/timecard", color: "bg-primary" },
  { title: "支払通知書", desc: "支払通知の管理", icon: CreditCard, url: "/shiharai", color: "bg-success" },
  { title: "商品管理", desc: "商品・材料の管理", icon: Package, url: "/shouhin", color: "bg-warning" },
  { title: "工具管理", desc: "工具の登録・履歴", icon: Wrench, url: "/kougu", color: "bg-accent" },
];

export default function Dashboard() {
  const navigate = useNavigate();
  const location = useLocation();
  const { profile, user, role } = useAuth();
  const queryClient = useQueryClient();
  const [showGenbaSelect, setShowGenbaSelect] = useState(false);
  const [selectedGenbaId, setSelectedGenbaId] = useState<string>("");
  const [genbaSearchQuery, setGenbaSearchQuery] = useState("");
  const isMobile = useIsMobile();

  // On mobile, defer non-critical queries to avoid freezing
  const [deferredReady, setDeferredReady] = useState(!isMobile);
  const [bikoExpanded, setBikoExpanded] = useState(false);
  const [bikoOpenIds, setBikoOpenIds] = useState<Set<string>>(new Set());
  useEffect(() => {
    if (isMobile && !deferredReady) {
      const t = setTimeout(() => setDeferredReady(true), 800);
      return () => clearTimeout(t);
    }
  }, [isMobile, deferredReady]);
  const isAdmin = role === "admin" || role === "manager";

  const canDenpyou = useEmployeePermission("denpyou_torikomi", "denpyou_employee_torikomi");

  // Collapsible sections - saved to localStorage
  const [dashProcessed, setDashProcessed] = useState<Record<string, string>>({});
  const SECTIONS_KEY = "dashboard-collapsed-sections";
  const [collapsed, setCollapsed] = useState<Record<string, boolean>>(() => {
    try {
      const saved = localStorage.getItem(SECTIONS_KEY);
      return saved ? JSON.parse(saved) : {};
    } catch { return {}; }
  });

  const toggleSection = useCallback((key: string) => {
    setCollapsed(prev => {
      const next = { ...prev, [key]: !prev[key] };
      localStorage.setItem(SECTIONS_KEY, JSON.stringify(next));
      return next;
    });
  }, []);

  const renderToggle = (sectionKey: string) => (
    <SectionToggleButton collapsed={!!collapsed[sectionKey]} onToggle={toggleSection} sectionKey={sectionKey} />
  );

  useEffect(() => {
    if (location.hash !== "#old-app-versions") return;

    let attempts = 0;
    const timer = window.setInterval(() => {
      attempts += 1;
      const anchor = document.getElementById("old-app-versions");
      const panel = document.getElementById("old-app-versions-panel");
      const container = document.getElementById("app-scroll-root");
      const scrollTarget = anchor ?? panel;
      const highlightTarget = panel ?? anchor;

      if (!scrollTarget || !container) {
        if (attempts >= 40) window.clearInterval(timer);
        return;
      }

      const containerRect = container.getBoundingClientRect();
      const elRect = scrollTarget.getBoundingClientRect();
      const top = container.scrollTop + (elRect.top - containerRect.top) - 16;
      container.scrollTo({ top: Math.max(top, 0), behavior: "smooth" });
      highlightTarget?.classList.add("ring-2", "ring-primary", "ring-offset-2");
      window.setTimeout(() => highlightTarget?.classList.remove("ring-2", "ring-primary", "ring-offset-2"), 2500);
      window.clearInterval(timer);
    }, 150);

    return () => window.clearInterval(timer);
  }, [location.hash]);

  const { data: genbaCount } = useQuery({
    queryKey: ["genba-count"],
    queryFn: async () => {
      const { count } = await supabase.from("genba").select("*", { count: "exact", head: true });
      return count || 0;
    },
  });

  const { data: seikyuCount } = useQuery({
    queryKey: ["seikyu-count"],
    queryFn: async () => {
      const { count } = await supabase.from("seikyu").select("*", { count: "exact", head: true });
      return count || 0;
    },
  });

  const { data: profileCount } = useQuery({
    queryKey: ["profile-count"],
    queryFn: async () => {
      const { count } = await supabase.from("profiles").select("*", { count: "exact", head: true });
      return count || 0;
    },
  });

  const { data: chumonCount } = useQuery({
    queryKey: ["chumon-count"],
    queryFn: async () => {
      const { count } = await supabase.from("chumon").select("*", { count: "exact", head: true });
      return count || 0;
    },
  });

  const { data: genbaList } = useQuery({
    queryKey: ["genba-list-active"],
    queryFn: async () => {
      const { data, error } = await supabase
        .from("genba")
        .select("id, genba_no, project_name, branch, manager_name, address, estimate_amount, start_date, end_date, status, client:torihikisaki!genba_client_id_fkey(company_name, client_no), sub:torihikisaki!genba_sub_contractor_id_fkey(company_name)")
        .order("genba_no", { ascending: false });
      if (error) throw error;
      return data;
    },
  });

  const [genbaShowAll, setGenbaShowAll] = useState(false);
  const activeGenba = genbaList?.filter((g: any) => g.status === "進行中" && !g.dashboard_hidden) || [];
  const displayGenba = genbaShowAll ? (genbaList || []) : activeGenba;

  const { data: vehicles } = useQuery({
    queryKey: ["sharyo-dashboard"],
    queryFn: async () => {
      const { data } = await supabase.from("sharyo").select("*").eq("is_visible", true);
      return data || [];
    },
    enabled: deferredReady,
  });

  const { data: sharyoDocsAll } = useQuery({
    queryKey: ["sharyo-docs-dashboard"],
    queryFn: async () => {
      const { data } = await supabase
        .from("sharyo_documents")
        .select("id, sharyo_id, category, expiry_date, file_name")
        .not("expiry_date", "is", null);
      return data || [];
    },
    enabled: deferredReady,
  });

  const { data: lendingKougu } = useQuery({
    queryKey: ["dashboard-lending-kougu"],
    queryFn: async () => {
      const { data } = await supabase
        .from("kougu_history")
        .select("*, kougu:kougu!kougu_history_kougu_id_fkey(tool_name, tool_code, serial_no, image_url)")
        .is("return_at", null)
        .order("checkout_at", { ascending: false });
      return data || [];
    },
    enabled: deferredReady,
  });

  const { data: kouguTotal } = useQuery({
    queryKey: ["dashboard-kougu-total"],
    queryFn: async () => {
      const { count } = await supabase.from("kougu").select("*", { count: "exact", head: true }).eq("is_active", true);
      return count || 0;
    },
    enabled: deferredReady,
  });

  const { data: kouguWithNotes } = useQuery({
    queryKey: ["dashboard-kougu-notes"],
    queryFn: async () => {
      const { data } = await supabase.from("kougu").select("id, tool_name, tool_code, notes").eq("is_active", true).not("notes", "is", null).neq("notes", "");
      return data || [];
    },
    enabled: deferredReady,
  });

  // Kougu history with AI alerts (不一致 or 軽微)
  const { data: kouguAlerts } = useQuery({
    queryKey: ["dashboard-kougu-alerts"],
    queryFn: async () => {
      const { data } = await supabase
        .from("kougu_history")
        .select("id, employee_name, genba_name, return_date, return_time, return_at, notes, kougu:kougu!kougu_history_kougu_id_fkey(tool_name, tool_code, serial_no)")
        .not("return_at", "is", null)
        .like("notes", "%【AI判定%")
        .order("return_at", { ascending: false })
        .limit(20);
      return (data || []).filter((h: any) => (h.notes?.includes("不一致") || h.notes?.includes("軽微")) && !h.notes?.startsWith("✓"));
    },
    enabled: deferredReady,
  });

  const handleAckAlert = async (historyId: string, currentNotes: string) => {
    await supabase.from("kougu_history").update({ notes: `✓${currentNotes}` }).eq("id", historyId);
    queryClient.invalidateQueries({ queryKey: ["dashboard-kougu-alerts"] });
  };

  // Pending seikyu (下書き / 発行済)
  const { data: pendingSeikyu } = useQuery({
    queryKey: ["dashboard-pending-seikyu"],
    queryFn: async () => {
      const { data } = await supabase
        .from("seikyu")
        .select("id, invoice_no, status, invoice_date, total_amount, client:torihikisaki!seikyu_client_id_fkey(company_name)")
        .in("status", ["下書き", "発行済"])
        .order("created_at", { ascending: false });
      return data || [];
    },
    enabled: deferredReady,
  });

  // Pending shiharai (下書き / 発行済)
  const { data: pendingShiharai } = useQuery({
    queryKey: ["dashboard-pending-shiharai"],
    queryFn: async () => {
      const { data } = await supabase
        .from("shiharai")
        .select("id, notice_no, status, payment_date, transfer_amount, client:torihikisaki!shiharai_client_id_fkey(company_name)")
        .in("status", ["下書き", "発行済"])
        .order("created_at", { ascending: false });
      return data || [];
    },
    enabled: deferredReady,
  });

  // Pending chumon (下書き / 発行済)
  const { data: pendingChumon } = useQuery({
    queryKey: ["dashboard-pending-chumon"],
    queryFn: async () => {
      const { data } = await supabase
        .from("chumon")
        .select("id, order_no, status, order_date, total_amount, client:torihikisaki!chumon_client_id_fkey(company_name)")
        .in("status", ["下書き", "発行済"])
        .order("created_at", { ascending: false });
      return data || [];
    },
    enabled: deferredReady,
  });

  // Pending kyujitsu for dashboard
  const { data: pendingKyujitsu } = useQuery({
    queryKey: ["dashboard-pending-kyujitsu"],
    queryFn: async () => {
      const { data } = await supabase
        .from("kyujitsu")
        .select("id, user_id, holiday_date, notes, approval_status")
        .eq("approval_status", "申請中")
        .order("holiday_date", { ascending: true });
      return data || [];
    },
    enabled: deferredReady,
  });

  const manualQueryOptions = {
    staleTime: Infinity,
    refetchOnWindowFocus: false,
    refetchOnReconnect: false,
    refetchOnMount: false,
    refetchInterval: false,
  } as const;

  // Pending maegari requests
  const { data: pendingMaegari } = useQuery({
    queryKey: ["dashboard-maegari"],
    queryFn: async () => {
      const { data } = await supabase
        .from("maegari_requests" as any)
        .select("*")
        .in("status", ["申請中", "1次承認"])
        .order("created_at", { ascending: false });
      return (data || []) as any[];
    },
    ...manualQueryOptions,
  });

  // Pending yuukyuu requests
  const { data: pendingYuukyuu } = useQuery({
    queryKey: ["dashboard-pending-yuukyuu"],
    queryFn: async () => {
      const { data } = await supabase
        .from("yuukyuu_records")
        .select("id, user_id, leave_date, reason, status, days_used, created_at")
        .eq("status", "申請中")
        .order("leave_date", { ascending: true });
      return data || [];
    },
  });

  const handleYuukyuuStatus = async (id: string, status: string) => {
    setDashProcessed(prev => ({ ...prev, [id]: status }));
    // Get the record first for notification
    const { data: record } = await supabase.from("yuukyuu_records").select("user_id, leave_date").eq("id", id).single();
    const { error } = await supabase.from("yuukyuu_records").update({
      status,
      approved_by: user?.id,
      approved_at: new Date().toISOString(),
    }).eq("id", id);
    if (error) {
      toast.error("更新に失敗しました");
    } else {
      toast.success(`有給申請を${status}しました`);
      queryClient.invalidateQueries({ queryKey: ["dashboard-pending-yuukyuu"] });
      // Send notification
      if (record) {
        const name = getDashboardPersonLabel(record.user_id);
        sendApprovalNotification({
          userId: record.user_id,
          employeeName: name,
          type: "有給休暇",
          status,
          date: record.leave_date,
        });
      }
    }
  };
  const handleMaegariStatus = async (id: string, status: string) => {
    setDashProcessed(prev => ({ ...prev, [id]: status === "承認" ? "承認済" : status }));
    // Find the request to check amount
    const req = (pendingMaegari || []).find((m: any) => m.id === id);
    const amount = Number(req?.kingaku) || 0;
    const needsSecondApproval = amount >= 50000;
    const firstApprover = req?.reviewed_by;
    const hasFirstApproval = !!firstApprover;

    if (status === "承認" && needsSecondApproval && hasFirstApproval && firstApprover !== user?.id) {
      // Second approval
      const { error } = await supabase.from("maegari_requests" as any).update({
        status: "承認",
        reviewed_by_2: user?.id,
        reviewed_at_2: new Date().toISOString(),
      } as any).eq("id", id);
      if (error) { toast.error("更新に失敗しました"); }
      else { toast.success("前借金申請を承認しました（2段階承認完了）"); queryClient.invalidateQueries({ queryKey: ["dashboard-maegari"] }); }
    } else if (status === "承認" && needsSecondApproval && !hasFirstApproval) {
      // First approval - mark as "1次承認"
      const { error } = await supabase.from("maegari_requests" as any).update({
        status: "1次承認",
        reviewed_by: user?.id,
        reviewed_at: new Date().toISOString(),
      } as any).eq("id", id);
      if (error) { toast.error("更新に失敗しました"); }
      else { toast.success("1次承認しました（¥50,000以上のため2段階承認が必要です）"); queryClient.invalidateQueries({ queryKey: ["dashboard-maegari"] }); }
    } else if (status === "承認" && needsSecondApproval && hasFirstApproval && firstApprover === user?.id) {
      toast.error("同じ承認者による2次承認はできません。別の管理者が承認してください。");
      return;
    } else {
      const { error } = await supabase.from("maegari_requests" as any).update({ status, reviewed_by: user?.id, reviewed_at: new Date().toISOString() } as any).eq("id", id);
      if (error) { toast.error("更新に失敗しました"); }
      else { toast.success(`前借金申請を${status}しました`); queryClient.invalidateQueries({ queryKey: ["dashboard-maegari"] }); }
    }
  };

  const pendingStatusOptions = ["下書き", "発行済", "箱済"];

  const handleKyujitsuStatus = async (id: string, status: string) => {
    setDashProcessed(prev => ({ ...prev, [id]: status }));
    const record = (pendingKyujitsu || []).find((k: any) => k.id === id);
    const { error } = await supabase.from("kyujitsu").update({ approval_status: status, approved_by: user?.id }).eq("id", id);
    if (error) {
      toast.error("更新に失敗しました");
      setDashProcessed(prev => { const n = { ...prev }; delete n[id]; return n; });
    } else {
      toast.success(`休日申請を${status === "承認済" ? "承認" : "却下"}しました`);
      queryClient.invalidateQueries({ queryKey: ["dashboard-pending-kyujitsu"] });
      queryClient.invalidateQueries({ queryKey: ["kyujitsu-records"] });
      if (record) {
        const name = getDashboardPersonLabel(record.user_id);
        sendApprovalNotification({
          userId: record.user_id,
          employeeName: name,
          type: "休日" as any,
          status,
          date: record.holiday_date,
        });
      }
    }
  };


  const handlePendingStatusChange = async (table: "seikyu" | "shiharai", recordId: string, newStatus: string) => {
      const { error } = await supabase.from(table as any).update({ status: newStatus } as any).eq("id", recordId);
    if (error) {
      toast.error("更新に失敗しました");
    } else {
      toast.success("ステータスを更新しました");
      queryClient.invalidateQueries({ queryKey: [`dashboard-pending-${table}`] });
      queryClient.invalidateQueries({ queryKey: [table] });
      queryClient.invalidateQueries({ queryKey: ["seikyu-count"] });
      queryClient.invalidateQueries({ queryKey: ["chumon-count"] });
    }
  };

  const { data: allProfiles } = useQuery({
    queryKey: ["profiles-dashboard-alerts"],
    queryFn: async () => {
      const { data } = await supabase.from("profiles").select("id, full_name, birth_date, last_health_checkup, is_active, user_id");
      return data || [];
    },
    enabled: deferredReady,
  });

  // Today's unsigned: people who clocked in today but didn't sign nippo
  const todayStr = new Intl.DateTimeFormat("en-CA", { timeZone: "Asia/Tokyo", year: "numeric", month: "2-digit", day: "2-digit" }).format(new Date());
  const sevenDaysAgo = (() => {
    const d = new Date();
    d.setDate(d.getDate() - 7);
    return new Intl.DateTimeFormat("en-CA", { timeZone: "Asia/Tokyo", year: "numeric", month: "2-digit", day: "2-digit" }).format(d);
  })();

  const { data: todayTimecards = [] } = useQuery({
    queryKey: ["dashboard-today-tc", todayStr],
    queryFn: async () => {
      const { data } = await supabase
        .from("timecard")
        .select("user_id, clock_in, clock_out, clock_in_teisei, clock_out_teisei, id, notes, work_date, timecard_details(genba_id, clock_in, clock_out, notes, genba:genba_id(project_name))")
        .eq("work_date", todayStr);
      return data || [];
    },
    ...manualQueryOptions,
  });

  // Recent timecards (last 7 days) for sankaku detection
  const { data: recentTimecards = [] } = useQuery({
    queryKey: ["dashboard-recent-tc", sevenDaysAgo, todayStr],
    queryFn: async () => {
      const { data } = await supabase
        .from("timecard")
        .select("user_id, clock_in, clock_out, clock_in_teisei, clock_out_teisei, id, notes, work_date, timecard_details(genba_id, clock_in, clock_out, notes, genba:genba_id(project_name))")
        .gte("work_date", sevenDaysAgo)
        .lte("work_date", todayStr)
        .order("work_date", { ascending: false });
      return data || [];
    },
    ...manualQueryOptions,
  });

  const { data: todaySignatures = [] } = useQuery({
    queryKey: ["dashboard-today-sigs", todayStr],
    queryFn: async () => {
      const { data } = await supabase
        .from("nippo_signatures")
        .select("user_id")
        .eq("work_date", todayStr);
      return data || [];
    },
    ...manualQueryOptions,
  });

  const { data: allProfilesFull } = useQuery({
    queryKey: ["profiles-dashboard-full"],
    queryFn: async () => {
      const { data } = await supabase.from("profiles").select("user_id, employee_no, full_name, is_active, role");
      return data || [];
    },
  });

  const genericDashboardNames = new Set(["管理者", "admin", "administrator"]);

  // Extract user-written biko from timecard notes (exclude system tags)
  const extractBikoText = (notes: string): string => {
    if (!notes) return "";
    const systemPatterns = [/^確認済$/m, /^管理者代理登録$/m, /^作業内容:[\s\S]*?(?=\n[^\s]|$)/m, /GPS:[\s\S]*/m];
    let cleaned = notes;
    systemPatterns.forEach(p => { cleaned = cleaned.replace(p, ""); });
    return cleaned.split("\n").map(l => l.trim()).filter(l => l.length > 0).join(" ");
  };

  const getDashboardPersonLabel = (userId: string) => {
    const matchedProfile = allProfilesFull?.find((pr: any) => pr.user_id === userId);
    const employeeNo = matchedProfile?.employee_no?.trim() || "";
    const profileName = matchedProfile?.full_name?.trim() || "";
    const metadataName =
      profile?.user_id === userId && typeof user?.user_metadata?.full_name === "string"
        ? user.user_metadata.full_name.trim()
        : "";

    const profileLabel = [employeeNo, profileName].filter(Boolean).join(" ");
    const metadataLabel = metadataName && !genericDashboardNames.has(metadataName)
      ? metadataName
      : "";
    const displayName = profileLabel || metadataLabel;

    return displayName || `社員(${userId.slice(0, 6)})`;
  };

  useEffect(() => {
    return () => {};
  }, []);

  const unsignedToday = (() => {
    if (!todayTimecards || !todaySignatures || !allProfilesFull) return [] as { name: string; unsigned: boolean; noWork: boolean; clockIn: string; genbaName: string; userId: string }[];
    const signedUserIds = new Set((todaySignatures || []).map((s: any) => s.user_id));
    const clockedUserIds = [...new Set(todayTimecards.map((t: any) => t.user_id))];
    return clockedUserIds
      .map(uid => {
        const userCards = todayTimecards.filter((t: any) => t.user_id === uid);
        const hasWork = userCards.some((t: any) =>
          ((t.timecard_details as any[]) || []).some((d: any) => d.notes && /作業内容:/.test(d.notes) && d.notes.replace(/作業内容:\s*/, "").replace(/\nGPS:[\s\S]*/, "").trim().length > 0)
        );
        const allConfirmed = userCards.every((t: any) => t.notes?.includes("確認済"));
        if (allConfirmed) return null;
        const isSigned = signedUserIds.has(uid);
        if (isSigned && hasWork) return null;
        const firstCard = userCards[0];
        const details = (firstCard?.timecard_details as any[]) || [];
        const latestDetail = details[details.length - 1];
        const genbaName = latestDetail?.genba?.project_name || "";
        return { name: getDashboardPersonLabel(uid), unsigned: !isSigned, noWork: !hasWork, clockIn: firstCard?.clock_in?.substring(0, 5) || "", genbaName, userId: uid };
      })
      .filter(Boolean) as { name: string; unsigned: boolean; noWork: boolean; clockIn: string; genbaName: string; userId: string }[];
  })();

  // 退勤未定: people who clocked in but haven't clocked out yet
  const missedClockOut = (() => {
    if (!todayTimecards || !allProfilesFull) return [] as { name: string; clockIn: string; genbaName: string; userId: string }[];
    return todayTimecards
      .filter((t: any) => t.clock_in && !t.clock_out)
      .map((t: any) => {
        const details = (t.timecard_details as any[]) || [];
        const latestDetail = details[details.length - 1];
        const genbaName = latestDetail?.genba?.project_name || "";
        return {
          name: getDashboardPersonLabel(t.user_id),
          clockIn: t.clock_in?.substring(0, 5) || "",
          genbaName,
          userId: t.user_id,
        };
      });
  })();

  // △ sankaku: employees with incomplete punches (worked < 4h) — last 7 days
  const sankakuRecent = (() => {
    if (!recentTimecards || !allProfilesFull) return [] as { name: string; clockIn: string; clockOut: string; hours: number; genbaName: string; userId: string; timecardId: string; workDate: string }[];
    return recentTimecards
      .filter((t: any) => {
        if (t.notes?.includes("確認済")) return false;
        const effectiveIn = t.clock_in_teisei || t.clock_in;
        const effectiveOut = t.clock_out_teisei || t.clock_out;
        if (!effectiveIn || !effectiveOut) return false;
        const details = (t.timecard_details as any[]) || [];
        let totalHours = 0;
        details.forEach((d: any) => {
          if (d.clock_in && d.clock_out) {
            const [ih, im] = d.clock_in.split(":").map(Number);
            const [oh, om] = d.clock_out.split(":").map(Number);
            totalHours += (oh * 60 + om - ih * 60 - im) / 60;
          }
        });
        if (totalHours === 0 && effectiveIn && effectiveOut) {
          const [ih, im] = effectiveIn.split(":").map(Number);
          const [oh, om] = effectiveOut.split(":").map(Number);
          totalHours = (oh * 60 + om - ih * 60 - im) / 60;
        }
        return totalHours > 0 && totalHours < 4;
      })
      .map((t: any) => {
        const effectiveIn = t.clock_in_teisei || t.clock_in;
        const effectiveOut = t.clock_out_teisei || t.clock_out;
        const details = (t.timecard_details as any[]) || [];
        let totalHours = 0;
        details.forEach((d: any) => {
          if (d.clock_in && d.clock_out) {
            const [ih, im] = d.clock_in.split(":").map(Number);
            const [oh, om] = d.clock_out.split(":").map(Number);
            totalHours += (oh * 60 + om - ih * 60 - im) / 60;
          }
        });
        if (totalHours === 0 && effectiveIn && effectiveOut) {
          const [ih, im] = effectiveIn.split(":").map(Number);
          const [oh, om] = effectiveOut.split(":").map(Number);
          totalHours = (oh * 60 + om - ih * 60 - im) / 60;
        }
        const latestDetail = details[details.length - 1];
        const genbaName = latestDetail?.genba?.project_name || "";
        return {
          name: getDashboardPersonLabel(t.user_id),
          clockIn: effectiveIn?.substring(0, 5) || "",
          clockOut: effectiveOut?.substring(0, 5) || "",
          hours: Math.round(totalHours * 10) / 10,
          genbaName,
          userId: t.user_id,
          timecardId: t.id,
          workDate: t.work_date,
        };
      });
  })();

  // 備考あり: employees who submitted biko (notes) today — extract from timecard.notes
  const bikoToday = (() => {
    if (!todayTimecards || !allProfilesFull) return [] as { name: string; biko: string; genbaName: string; userId: string; timecardId: string }[];
    return todayTimecards
      .filter((t: any) => {
        if (!t.notes) return false;
        // Extract biko lines (exclude system tags like 確認済, 管理者代理登録, 作業内容:)
        const bikoText = extractBikoText(t.notes);
        return bikoText.length > 0;
      })
      .map((t: any) => {
        const details = (t.timecard_details as any[]) || [];
        const latestDetail = details[details.length - 1];
        const genbaName = latestDetail?.genba?.project_name || "";
        return {
          name: getDashboardPersonLabel(t.user_id),
          biko: extractBikoText(t.notes),
          genbaName,
          userId: t.user_id,
          timecardId: t.id,
        };
      });
  })();

  const handleSankakuConfirm = async (timecardId: string, name: string) => {
    const tc = recentTimecards?.find((t: any) => t.id === timecardId) || todayTimecards?.find((t: any) => t.id === timecardId);
    const existingNotes = tc?.notes || "";
    const newNotes = existingNotes ? `${existingNotes}\n確認済` : "確認済";
    const { error } = await supabase.from("timecard").update({ notes: newNotes }).eq("id", timecardId);
    if (error) {
      toast.error("更新に失敗しました");
    } else {
      toast.success(`${name} — 打刻確認済 ✅`);
      queryClient.invalidateQueries({ queryKey: ["dashboard-today-tc"] });
      queryClient.invalidateQueries({ queryKey: ["dashboard-recent-tc"] });
    }
  };

  const dashAlerts: { icon: typeof Car; label: string; detail: string; daysLeft: number; severity: "danger" | "warning" | "info"; updateTable?: string; updateId?: string; updateField?: string; currentDate?: string }[] = [];
  const today = new Date();

  (vehicles || []).forEach((v: any) => {
    [
      { field: v.inspection_expiry, detail: "車検満了", dbField: "inspection_expiry" },
      { field: v.liability_insurance_expiry, detail: "自賠責保険", dbField: "liability_insurance_expiry" },
      { field: v.optional_insurance_expiry, detail: "任意保険", dbField: "optional_insurance_expiry" },
    ].forEach(({ field, detail, dbField }) => {
      if (!field) return;
      const days = differenceInDays(parseISO(field), today);
      if (days <= 90) {
        dashAlerts.push({
          icon: Car, label: `${v.vehicle_name} (${v.vehicle_no})`,
          detail: `${detail}: ${format(parseISO(field), "yyyy/MM/dd")}`,
          daysLeft: days, severity: days < 0 ? "danger" : days <= 30 ? "danger" : "warning",
          updateTable: "sharyo", updateId: v.id, updateField: dbField, currentDate: field,
        });
      }
    });
  });

  // Document expiry alerts
  const docCatLabels: Record<string, string> = {
    shaken: "車検証", jibaiseki: "自賠責", ninni: "AIG自動車保険", recycle: "リサイクル書",
    kiroku: "自動車検査証記録事項", photo: "車の写真", oil: "オイル交換", tire: "タイヤ交換", other: "その他",
  };
  (sharyoDocsAll || []).forEach((d: any) => {
    if (!d.expiry_date) return;
    const days = differenceInDays(parseISO(d.expiry_date), today);
    if (days <= 60) {
      const vehicle = (vehicles || []).find((v: any) => v.id === d.sharyo_id);
      const vLabel = vehicle ? `${vehicle.vehicle_name} (${vehicle.vehicle_no})` : "車両";
      dashAlerts.push({
        icon: FileText, label: vLabel,
        detail: `${docCatLabels[d.category] || d.category}: ${format(parseISO(d.expiry_date), "yyyy/MM/dd")}${days < 0 ? " (期限切れ)" : ""}`,
        daysLeft: days, severity: days < 0 ? "danger" : days <= 7 ? "danger" : days <= 30 ? "warning" : "info",
      });
    }
  });

  (allProfiles || []).forEach((p: any) => {
    if (p.birth_date) {
      const bd = parseISO(p.birth_date);
      const thisYearBd = new Date(today.getFullYear(), bd.getMonth(), bd.getDate());
      const days = differenceInDays(thisYearBd, today);
      if (days >= 0 && days <= 14) {
        dashAlerts.push({
          icon: Cake, label: p.full_name,
          detail: `誕生日: ${format(thisYearBd, "MM/dd")}${days === 0 ? " 🎉 今日！" : ` (あと${days}日)`}`,
          daysLeft: days, severity: "info",
        });
      }
    }
    if (p.last_health_checkup) {
      const expiry = addYears(parseISO(p.last_health_checkup), 1);
      const days = differenceInDays(expiry, today);
      if (days <= 90) {
        dashAlerts.push({
          icon: Heart, label: p.full_name,
          detail: `健康診断: ${format(expiry, "yyyy/MM/dd")}${days < 0 ? " (期限切れ)" : ""}`,
          daysLeft: days, severity: days < 0 ? "danger" : days <= 30 ? "danger" : "warning",
          updateTable: "profiles", updateId: p.id, updateField: "last_health_checkup", currentDate: p.last_health_checkup,
        });
      }
    }
  });

  dashAlerts.sort((a, b) => {
    const sev = { danger: 0, warning: 1, info: 2 };
    return sev[a.severity] - sev[b.severity] || a.daysLeft - b.daysLeft;
  });

  const handleAlertDateUpdate = async (alert: typeof dashAlerts[0], date: Date) => {
    if (!alert.updateTable || !alert.updateId || !alert.updateField) return;
    const dateStr = format(date, "yyyy-MM-dd");
    const { error } = await supabase
      .from(alert.updateTable as any)
      .update({ [alert.updateField]: dateStr } as any)
      .eq("id", alert.updateId);
    if (error) {
      toast.error(`エラー: ${error.message}`);
    } else {
      toast.success(`${alert.label} の日付を更新しました`);
      queryClient.invalidateQueries({ queryKey: ["sharyo-alerts"] });
      queryClient.invalidateQueries({ queryKey: ["profiles-alerts"] });
      queryClient.invalidateQueries({ queryKey: ["profiles"] });
      queryClient.invalidateQueries({ queryKey: ["sharyo"] });
      queryClient.invalidateQueries({ queryKey: ["dashboard-vehicles"] });
      queryClient.invalidateQueries({ queryKey: ["profiles-dashboard"] });
    }
  };

  const stats = [
    { label: "現場数", value: String(genbaCount ?? 0), icon: Building2, sub: `進行中 ${activeGenba.length}件`, url: "/genba", color: "text-primary" },
    { label: "請求書", value: String(seikyuCount ?? 0), icon: FileText, sub: `下書き ${pendingSeikyu?.length || 0}件`, url: "/seikyu", color: "text-emerald-600 dark:text-emerald-400" },
    { label: "社員数", value: String(profileCount ?? 0), icon: Users, sub: "アクティブ", url: "/shain", color: "text-blue-600 dark:text-blue-400" },
    { label: "注文書", value: String(chumonCount ?? 0), icon: ClipboardList, sub: `下書き ${pendingChumon?.length || 0}件`, url: "/chumon", color: "text-amber-600 dark:text-amber-400" },
  ];

  const handleDenpyoTorikomi = () => {
    // Always open the picker so the user explicitly chooses the obra
    setShowGenbaSelect(true);
  };

  const handleGenbaSelected = () => {
    if (!selectedGenbaId) {
      toast.error("現場を選択してください");
      return;
    }
    setShowGenbaSelect(false);
    navigate(`/genba/${selectedGenbaId}?denpyo=1`);
  };

  const SectionHeader = ({ icon: Icon, title, iconColor = "text-primary", children }: { icon?: any; title: string; iconColor?: string; children?: React.ReactNode }) => (
    <div className="flex items-center gap-3 mb-3 mt-8 first:mt-0 border-b-2 border-primary/30 pb-2">
      {Icon && (
        <div className="w-7 h-7 rounded-md bg-primary/10 flex items-center justify-center shrink-0">
          <Icon className={cn("w-4 h-4", iconColor)} />
        </div>
      )}
      <h2 className="text-sm font-bold text-primary tracking-wide flex-1">{title}</h2>
      {children}
    </div>
  );

  return (
    <AppLayout icon={Home} title="ダッシュボード ー ようこそ、JBX GROUPへ">
      {/* 伝票取込 quick action */}
      {canDenpyou && (
      <div className="mb-6">
        <Button
          size="lg"
          className="w-full sm:w-auto gap-2 text-base shadow-sm"
          onClick={handleDenpyoTorikomi}
        >
          <Camera className="h-5 w-5" />
          伝票取込（写真で登録）
        </Button>
      </div>
      )}

      {isAdmin && (
      <div className="grid grid-cols-2 lg:grid-cols-4 gap-3 mb-6">
        {stats.map((stat) => (
          <Card
            key={stat.label}
            className="border-0 shadow-md cursor-pointer hover:shadow-lg transition-all group bg-card/80 backdrop-blur-sm"
            onClick={() => navigate(stat.url)}
          >
            <CardContent className="p-4">
              <div className="flex items-center justify-between mb-1">
                <p className="text-[11px] text-muted-foreground font-semibold uppercase tracking-wider">{stat.label}</p>
                <div className={cn("w-8 h-8 rounded-lg flex items-center justify-center bg-primary/10", stat.color)}>
                  <stat.icon className="w-4 h-4" />
                </div>
              </div>
              <span className="text-2xl font-bold text-foreground">{stat.value}</span>
              <p className="text-[10px] text-muted-foreground mt-0.5">{stat.sub}</p>
            </CardContent>
          </Card>
        ))}
      </div>
      )}

      {/* Quick Access — moved to top for fast navigation */}
      <SectionHeader icon={Package} title="クイックアクセス">
        {renderToggle("quickAccess")}
      </SectionHeader>
      {!collapsed["quickAccess"] && (
      <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
        {quickLinks.map((link) => (
          <Card
            key={link.title}
            className="border-0 shadow-md cursor-pointer hover:shadow-lg transition-all group"
            onClick={() => navigate(link.url)}
          >
            <CardContent className="p-5 flex items-start gap-4">
              <div className={`w-10 h-10 rounded-lg ${link.color} flex items-center justify-center flex-shrink-0`}>
                <link.icon className="w-5 h-5 text-primary-foreground" />
              </div>
              <div>
                <p className="text-sm font-semibold text-foreground group-hover:text-primary transition-colors">
                  {link.title}
                </p>
                <p className="text-xs text-muted-foreground mt-0.5">{link.desc}</p>
              </div>
            </CardContent>
          </Card>
        ))}
      </div>
      )}

      {/* Pending Panel */}
      {isAdmin && <PendingPanel />}

      {/* Old App Versions */}
      {isAdmin && (
        <div id="old-app-versions" className="my-4 scroll-mt-20">
          <LazyWidget minHeight={120}><OldAppVersionsPanel /></LazyWidget>
        </div>
      )}

      {/* Recent Drawing Activity */}
      {isAdmin && <div className="my-4"><LazyWidget minHeight={120}><RecentDrawingActivity /></LazyWidget></div>}

      {/* Live Presence + Birthday */}
      {isAdmin && (
        <div className="grid grid-cols-1 lg:grid-cols-2 gap-4 my-4">
          <LazyWidget minHeight={200}><LivePresence /></LazyWidget>
          <LazyWidget minHeight={200}><BirthdayPanel /></LazyWidget>
        </div>
      )}

      {/* GPS Tracking Map - admin/manager only */}
      {isAdmin && (
        <div className="my-4">
          <LazyWidget minHeight={400}><LiveGpsMap /></LazyWidget>
        </div>
      )}

      {/* Monthly Target + Employee Ranking */}
      {isAdmin && (
      <div className="grid grid-cols-1 lg:grid-cols-2 gap-4 my-6">
        <MonthlyTargetBar />
        <LazyWidget minHeight={300}><EmployeeRanking /></LazyWidget>
      </div>
      )}


      <Card className="mb-4 border-0 shadow-md">
        <CardHeader className="pb-2 bg-orange-600 text-white rounded-t-lg">
          <div className="flex items-center justify-between">
            <div className="flex items-center gap-2 flex-1">
              {renderToggle("genba")}
              <CardTitle className="text-sm flex items-center gap-2 cursor-pointer font-bold text-primary-foreground" onClick={() => navigate("/genba")}>
                <Building2 className="w-4 h-4" />
                現場一覧 — {activeGenba.length}件{genbaShowAll ? ` (全${genbaList?.length || 0}件表示中)` : ""}
              </CardTitle>
            </div>
            <Button variant="ghost" size="sm" className="h-7 text-xs gap-1" onClick={() => setGenbaShowAll(!genbaShowAll)}>
              {genbaShowAll ? <><EyeOff className="w-3 h-3" />進行中のみ</> : <><Eye className="w-3 h-3" />全件表示</>}
            </Button>
          </div>
        </CardHeader>
        {!collapsed["genba"] && (
        <CardContent className="p-0">
          <div className="overflow-auto max-h-[400px]">
            <Table>
              <TableHeader>
                <TableRow className="text-[11px] bg-primary/10">
                  <TableHead className="w-20 sticky top-0 bg-primary text-primary-foreground font-bold">管理No</TableHead>
                  <TableHead className="sticky top-0 bg-primary text-primary-foreground font-bold">請求先</TableHead>
                  <TableHead className="sticky top-0 bg-primary text-primary-foreground font-bold hidden sm:table-cell">支店</TableHead>
                  <TableHead className="sticky top-0 bg-primary text-primary-foreground font-bold">工事名称</TableHead>
                  <TableHead className="sticky top-0 bg-primary text-primary-foreground font-bold hidden sm:table-cell">担当者</TableHead>
                  <TableHead className="sticky top-0 bg-primary text-primary-foreground font-bold hidden md:table-cell text-right">見積金額</TableHead>
                  <TableHead className="sticky top-0 bg-primary text-primary-foreground font-bold hidden lg:table-cell">施工日</TableHead>
                  <TableHead className="sticky top-0 bg-primary text-primary-foreground font-bold hidden lg:table-cell">完了日</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {displayGenba.map((g: any, idx: number) => (
                  <TableRow
                    key={g.id}
                    className={cn("text-xs cursor-pointer hover:bg-primary/5 transition-colors", idx % 2 === 0 ? "bg-card" : "bg-muted/30")}
                    onClick={() => navigate(`/genba/${g.id}`)}
                  >
                    <TableCell className="font-mono text-[11px] font-medium">{g.genba_no}</TableCell>
                    <TableCell className="truncate max-w-[120px]">
                      {(g.client as any)?.company_name || "—"}
                    </TableCell>
                    <TableCell className="hidden sm:table-cell">{g.branch || "—"}</TableCell>
                    <TableCell className="font-medium truncate max-w-[200px]">{g.project_name}</TableCell>
                    <TableCell className="hidden sm:table-cell truncate max-w-[80px]">{g.manager_name || "—"}</TableCell>
                    <TableCell className="hidden md:table-cell text-right font-mono">
                      {g.estimate_amount ? `¥${Number(g.estimate_amount).toLocaleString()}` : "—"}
                    </TableCell>
                    <TableCell className="hidden lg:table-cell text-muted-foreground">
                      {g.start_date ? g.start_date.replace(/-/g, "/").slice(2) : "—"}
                    </TableCell>
                    <TableCell className="hidden lg:table-cell text-muted-foreground">
                      {g.end_date ? g.end_date.replace(/-/g, "/").slice(2) : "—"}
                    </TableCell>
                  </TableRow>
                ))}
                {displayGenba.length === 0 && (
                  <TableRow>
                    <TableCell colSpan={8} className="text-center text-muted-foreground py-4">現場データがありません</TableCell>
                  </TableRow>
                )}
              </TableBody>
            </Table>
          </div>
        </CardContent>
        )}
      </Card>

      <NinkuAlert collapsed={!!collapsed["ninkuAlert"]} onToggle={() => toggleSection("ninkuAlert")} />

      {missedClockOut.length > 0 && (
        <Card className="mb-4 border-0 shadow-md overflow-hidden">
          <CardHeader className="pb-2 bg-red-600 text-white rounded-t-lg">
            <CardTitle className="text-sm flex items-center gap-2 text-primary-foreground">
              {renderToggle("missedClockOut")}
              <Clock className="w-4 h-4" />
              本日 退勤未定 ({missedClockOut.length}名)
              <Button
                variant="ghost"
                size="sm"
                className="h-6 px-2 text-[10px] ml-auto"
                onClick={(e) => {
                  e.stopPropagation();
                  const lines = missedClockOut.map(item => {
                    const genba = item.genbaName ? ` 📍${item.genbaName}` : "";
                    return `${item.name}${genba} 出勤${item.clockIn}`;
                  });
                  const text = `本日 退勤未定 (${missedClockOut.length}名)\n${lines.join("\n")}`;
                  navigator.clipboard.writeText(text);
                  toast.success("コピーしました");
                }}
              >
                📋 コピー
              </Button>
            </CardTitle>
          </CardHeader>
          {!collapsed["missedClockOut"] && (
          <CardContent>
            <div className="space-y-1.5">
              {missedClockOut.map((item, i) => (
                <div
                  key={i}
                  className="flex items-center gap-3 p-2 rounded-md border border-amber-400/30 bg-amber-50 dark:bg-amber-900/20 cursor-pointer hover:bg-amber-100 dark:hover:bg-amber-900/30 transition-colors"
                  onClick={() => navigate(`/timecard?user=${item.userId}`)}
                >
                  <Badge variant="outline" className="text-xs border-amber-500 text-amber-700 dark:text-amber-300 bg-amber-100 dark:bg-amber-900/40 shrink-0">
                    退勤未定
                  </Badge>
                  <div className="flex-1 min-w-0">
                    <span className="text-xs font-bold">{item.name}</span>
                    {item.genbaName && <span className="text-[11px] text-muted-foreground ml-2">📍 {item.genbaName}</span>}
                  </div>
                  <span className="text-xs font-mono text-muted-foreground shrink-0">出勤 {item.clockIn}</span>
                </div>
              ))}
            </div>
          </CardContent>
          )}
        </Card>
      )}

      {/* Sankaku — incomplete punches (last 7 days) */}
      {sankakuRecent.length > 0 && (
        <Card className="mb-4 border-0 shadow-md overflow-hidden">
          <CardHeader className="pb-2 bg-amber-500 text-white rounded-t-lg">
            <CardTitle className="text-sm flex items-center gap-2 text-primary-foreground">
              {renderToggle("sankaku")}
              <AlertTriangle className="w-4 h-4" />
              △半日・打刻不備 ({sankakuRecent.length}件 / 直近7日)
              <Button
                variant="ghost"
                size="sm"
                className="h-6 px-2 text-[10px] ml-auto"
                onClick={(e) => {
                  e.stopPropagation();
                  const lines = sankakuRecent.map(item => {
                    const genba = item.genbaName ? ` 📍${item.genbaName}` : "";
                    const dateLabel = item.workDate === todayStr ? "本日" : item.workDate.substring(5).replace("-", "/");
                    return `[${dateLabel}] ${item.name}${genba} ${item.clockIn}〜${item.clockOut} (${item.hours}h)`;
                  });
                  const text = `△半日・打刻不備 (${sankakuRecent.length}件)\n${lines.join("\n")}`;
                  navigator.clipboard.writeText(text);
                  toast.success("コピーしました");
                }}
              >
                📋 コピー
              </Button>
            </CardTitle>
          </CardHeader>
          {!collapsed["sankaku"] && (
          <CardContent>
            <p className="text-[11px] text-muted-foreground mb-2">出退勤の合計が4時間未満の社員（打刻忘れの可能性あり）— 直近7日間</p>
            <div className="space-y-1.5">
              {sankakuRecent.map((item, i) => {
                const dateLabel = item.workDate === todayStr ? "本日" : item.workDate.substring(5).replace("-", "/");
                return (
                <div
                  key={i}
                  className="flex items-center gap-2 p-2 rounded-md border border-orange-300/30 bg-orange-50/50 dark:bg-orange-900/10 cursor-pointer hover:bg-orange-100/50 dark:hover:bg-orange-900/20 transition-colors"
                  onClick={() => navigate(`/timecard?user=${item.userId}`)}
                >
                  <Badge variant="outline" className="text-[10px] border-muted text-muted-foreground shrink-0 font-normal">
                    {dateLabel}
                  </Badge>
                  <Badge variant="outline" className="text-xs border-orange-400 text-orange-700 dark:text-orange-300 bg-orange-100/50 dark:bg-orange-900/20 shrink-0">
                    △ {item.hours}h
                  </Badge>
                  <div className="flex-1 min-w-0">
                    <span className="text-xs font-bold">{item.name}</span>
                    {item.genbaName && <span className="text-[11px] text-muted-foreground ml-2">📍 {item.genbaName}</span>}
                  </div>
                  <span className="text-xs font-mono text-muted-foreground shrink-0">{item.clockIn}〜{item.clockOut}</span>
                  <Button
                    variant="ghost"
                    size="sm"
                    className="h-6 px-2 text-[10px] shrink-0 text-green-600 hover:text-green-700 hover:bg-green-100/50"
                    onClick={(e) => {
                      e.stopPropagation();
                      handleSankakuConfirm(item.timecardId, item.name);
                    }}
                  >
                    ✅ OK
                  </Button>
                </div>
                );
              })}
            </div>
          </CardContent>
          )}
        </Card>
      )}

      {/* Unsigned Today */}
      {unsignedToday.length > 0 && (
        <Card className="mb-4 border-0 shadow-md overflow-hidden">
          <CardHeader className="pb-2 bg-indigo-600 text-white rounded-t-lg">
            <CardTitle className="text-sm flex items-center gap-2 text-primary-foreground">
              {renderToggle("unsigned")}
              <PenLine className="w-4 h-4" />
              本日 未署名・作業内容なし ({unsignedToday.length}名)
              <Button
                variant="ghost"
                size="sm"
                className="h-6 px-2 text-[10px] ml-auto"
                onClick={(e) => {
                  e.stopPropagation();
                   const text = `本日 未署名・作業内容なし (${unsignedToday.length}名)\n${unsignedToday.map(u => {
                    const tags = [u.unsigned ? "未署名" : "", u.noWork ? "作業内容なし" : ""].filter(Boolean).join("・");
                    const genba = u.genbaName ? ` 📍 ${u.genbaName}` : "";
                    const time = u.clockIn ? ` 出勤${u.clockIn}` : "";
                    return `${u.name} — ${tags}${genba}${time}`;
                  }).join("\n")}`;
                  navigator.clipboard.writeText(text);
                  toast.success("コピーしました");
                }}
              >
                📋 コピー
              </Button>
            </CardTitle>
          </CardHeader>
          {!collapsed["unsigned"] && (
          <CardContent>
            <p className="text-[11px] text-muted-foreground mb-2">出勤したが日報サイン or 作業内容がまだの社員</p>
            <div className="space-y-1.5">
              {unsignedToday.map((u, i) => {
                const userCard = todayTimecards.find((t: any) => t.user_id === u.userId);
                return (
                <div key={i} className="flex items-center gap-2 px-2 py-1.5 rounded-md bg-destructive/5 border border-destructive/20 cursor-pointer hover:bg-destructive/10 transition-colors" onClick={() => navigate(`/timecard?user=${u.userId}`)}>
                  <Badge variant={u.unsigned ? "destructive" : "outline"} className="text-[10px] shrink-0">
                    {[u.unsigned ? "未署名" : "", u.noWork ? "作業内容なし" : ""].filter(Boolean).join("・")}
                  </Badge>
                  <div className="flex-1 min-w-0">
                    <span className="text-xs font-bold">{u.name}</span>
                    {u.genbaName && <span className="text-[11px] text-muted-foreground ml-2">📍 {u.genbaName}</span>}
                  </div>
                  {u.clockIn && <span className="text-xs font-mono text-muted-foreground shrink-0">出勤 {u.clockIn}</span>}
                  {userCard && (
                    <Button variant="outline" size="sm" className="h-6 px-2 text-[10px] shrink-0" onClick={(e) => { e.stopPropagation(); handleSankakuConfirm((userCard as any).id, u.name); }}>
                      ✅ OK
                    </Button>
                  )}
                </div>
                );
              })}
            </div>
          </CardContent>
          )}
        </Card>
      )}

      {/* 備考あり Today */}
      {bikoToday.length > 0 && (
        <Card className="mb-4 border-0 shadow-md overflow-hidden">
          <CardHeader className="pb-2 bg-sky-600 text-white rounded-t-lg">
            <CardTitle className="text-sm flex items-center gap-2 text-primary-foreground">
              {renderToggle("biko")}
              <FileText className="w-4 h-4" />
              本日 備考あり ({bikoToday.length}件)
              <Button
                variant="ghost"
                size="sm"
                className="h-6 px-2 text-[10px] ml-auto"
                onClick={(e) => {
                  e.stopPropagation();
                  const text = `本日 備考あり (${bikoToday.length}件)\n${bikoToday.map(b => `${b.name}${b.genbaName ? ` 📍 ${b.genbaName}` : ""}: ${b.biko}`).join("\n")}`;
                  navigator.clipboard.writeText(text);
                  toast.success("コピーしました");
                }}
              >
                📋 コピー
              </Button>
            </CardTitle>
          </CardHeader>
          {!collapsed["biko"] && (
          <CardContent>
            <p className="text-[11px] text-muted-foreground mb-2">退勤時に備考を記入した社員</p>
            <div className="space-y-1.5">
              {bikoToday.map((b, i) => (
                <div key={i} className="flex items-center gap-2 px-2 py-1.5 rounded-md bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 cursor-pointer hover:bg-blue-100 dark:hover:bg-blue-900/30 transition-colors" onClick={() => navigate(`/timecard?user=${b.userId}`)}>
                  <Badge variant="outline" className="text-[10px] shrink-0 border-blue-400 text-blue-700 dark:text-blue-300">📝 備考</Badge>
                  <div className="flex-1 min-w-0">
                    <span className="text-xs font-bold">{b.name}</span>
                    {b.genbaName && <span className="text-[11px] text-muted-foreground ml-2">📍 {b.genbaName}</span>}
                    <p className="text-[11px] text-foreground mt-0.5 truncate">{b.biko}</p>
                  </div>
                  <Button variant="outline" size="sm" className="h-6 px-2 text-[10px] shrink-0" onClick={(e) => { e.stopPropagation(); handleSankakuConfirm(b.timecardId, b.name); }}>
                    ✅ OK
                  </Button>
                </div>
              ))}
            </div>
          </CardContent>
          )}
        </Card>
      )}

      <Card className="mb-4 border-0 shadow-md overflow-hidden">
        <CardHeader className="pb-2 bg-purple-600 text-white rounded-t-lg">
          <CardTitle className="text-sm flex items-center gap-2 text-primary-foreground">
            <span className="flex items-center gap-2 cursor-pointer" onClick={() => navigate("/kougu")}>
              {renderToggle("kougu")}
              <Wrench className="w-4 h-4" />
              工具管理 — 全{kouguTotal || 0}台 ／ 貸出中 {lendingKougu?.length || 0}件 ／ 在庫 {(kouguTotal || 0) - (lendingKougu?.length || 0)}台
            </span>
            <Button variant="outline" size="sm" className="h-6 px-2 text-xs ml-auto" onClick={(e) => { e.stopPropagation(); navigate("/kougu"); }}>詳細</Button>
            <Button variant="ghost" size="sm" className="h-6 px-2 text-xs" onClick={(e) => {
              e.stopPropagation();
              const header = `工具管理 — 全${kouguTotal || 0}台 ／ 貸出中 ${lendingKougu?.length || 0}件 ／ 在庫 ${(kouguTotal || 0) - (lendingKougu?.length || 0)}台`;
              const lines = [header];
              if (lendingKougu && lendingKougu.length > 0) {
                lines.push("\n貸出中:");
                lendingKougu.forEach((h: any) => {
                  const name = (h.kougu as any)?.tool_name || "—";
                  const code = (h.kougu as any)?.tool_code || (h.kougu as any)?.serial_no || "";
                  const emp = h.employee_name || "未定";
                  const genba = h.genba_name ? ` ｜ ${h.genba_name}` : "";
                  lines.push(`  ${name}(${code}) → ${emp}${genba}`);
                });
              }
              navigator.clipboard.writeText(lines.join("\n"));
              toast.success("コピーしました");
            }}>📋 コピー</Button>
          </CardTitle>
        </CardHeader>
        {!collapsed["kougu"] && (
        <CardContent className="space-y-2">
          {/* 貸出中リスト */}
          {lendingKougu && lendingKougu.length > 0 && (
            <div>
              <div className="text-xs font-medium text-muted-foreground mb-1">貸出中</div>
              <div className="space-y-1">
                {lendingKougu.map((h: any) => (
                  <div key={h.id} className="flex items-center gap-2 text-xs p-1.5 rounded bg-warning/5 border border-warning/20">
                    {(h.kougu as any)?.image_url && (
                      <img src={(h.kougu as any).image_url} alt="" className="w-8 h-8 object-cover rounded" />
                    )}
                    <div className="flex-1 min-w-0">
                      <span className="font-medium">{(h.kougu as any)?.tool_name || "—"}</span>
                      <span className="text-muted-foreground ml-1">({(h.kougu as any)?.tool_code || (h.kougu as any)?.serial_no})</span>
                      <div className="text-muted-foreground truncate">
                        → {h.employee_name || "未定"} {h.genba_name ? `｜ ${h.genba_name}` : ""}
                      </div>
                    </div>
                    {h.notes && <Badge variant="outline" className="text-[10px] border-destructive text-destructive shrink-0">📝 {h.notes}</Badge>}
                  </div>
                ))}
              </div>
            </div>
          )}
          {/* 備考アラート */}
          {kouguWithNotes && kouguWithNotes.length > 0 && (
            <div>
              <button
                type="button"
                onClick={() => setBikoExpanded((v) => !v)}
                className="flex items-center gap-1 text-xs font-medium text-muted-foreground hover:text-foreground transition-colors mb-1"
              >
                {bikoExpanded ? <ChevronDown className="w-3.5 h-3.5" /> : <ChevronUp className="w-3.5 h-3.5 rotate-90" />}
                <AlertTriangle className="w-3.5 h-3.5 text-accent" />
                <span>備考・注意 ({kouguWithNotes.length}件)</span>
              </button>
              {bikoExpanded && (
                <div className="flex flex-col gap-1 pl-4 border-l-2 border-accent/30">
                  {kouguWithNotes.map((k: any) => {
                    const open = bikoOpenIds.has(k.id);
                    return (
                      <div key={k.id}>
                        <button
                          type="button"
                          onClick={() => {
                            setBikoOpenIds((prev) => {
                              const next = new Set(prev);
                              if (next.has(k.id)) next.delete(k.id);
                              else next.add(k.id);
                              return next;
                            });
                          }}
                          className="flex items-center gap-1 text-[11px] hover:text-accent transition-colors text-left"
                        >
                          {open ? <ChevronDown className="w-3 h-3 shrink-0" /> : <ChevronUp className="w-3 h-3 rotate-90 shrink-0" />}
                          <span className="font-medium">{k.tool_code || k.tool_name}</span>
                          {k.tool_code && k.tool_name && <span className="text-muted-foreground">({k.tool_name})</span>}
                        </button>
                        {open && (
                          <div className="ml-4 mt-0.5 mb-1 text-[11px] text-muted-foreground whitespace-pre-line p-1.5 rounded bg-muted/50 border border-border">
                            {k.notes}
                          </div>
                        )}
                      </div>
                    );
                  })}
                </div>
              )}
            </div>
          )}
          {/* AI返却アラート */}
          {kouguAlerts && kouguAlerts.length > 0 && (
            <div>
              <div className="text-xs font-medium flex items-center gap-1 mb-1">
                <AlertTriangle className="w-3.5 h-3.5 text-destructive" />
                <span className="text-destructive">返却時AI検知アラート</span>
              </div>
              <div className="space-y-1.5">
                {kouguAlerts.map((h: any) => {
                  const isAlert = h.notes?.includes("不一致");
                  const aiMatch = h.notes?.match(/【AI判定[^】]*】([\s\S]*)/);
                  const aiText = aiMatch ? aiMatch[1].trim() : h.notes;
                  return (
                    <div key={h.id} className={`p-2 rounded border text-[11px] leading-relaxed ${
                      isAlert 
                        ? "bg-destructive/10 border-destructive/20 text-destructive" 
                        : "bg-yellow-50 dark:bg-yellow-900/20 border-yellow-200 dark:border-yellow-700/30 text-yellow-700 dark:text-yellow-400"
                    }`}>
                      <div className="flex items-center gap-2 mb-0.5">
                        <span className="font-semibold">{(h.kougu as any)?.tool_name || "—"}</span>
                        <span className="text-muted-foreground">({(h.kougu as any)?.tool_code || (h.kougu as any)?.serial_no || ""})</span>
                        <span className="ml-auto text-muted-foreground">{h.return_date || (h.return_at ? format(new Date(h.return_at), "yyyy/MM/dd") : "")} {h.return_time || (h.return_at ? format(new Date(h.return_at), "HH:mm") : "")}</span>
                      </div>
                      <div className="flex items-center gap-1 mb-0.5">
                        <Users className="w-3 h-3 shrink-0" />
                        <span className="font-medium">{h.employee_name || "不明"}</span>
                        {h.genba_name && <span className="text-muted-foreground">｜{h.genba_name}</span>}
                      </div>
                      <div className="flex items-center gap-2">
                        <div className="whitespace-pre-line flex-1">{aiText}</div>
                        <Button size="sm" variant="outline" className="shrink-0 text-[10px] h-6 px-2" onClick={() => handleAckAlert(h.id, h.notes || "")}>
                          OK
                        </Button>
                      </div>
                    </div>
                  );
                })}
              </div>
            </div>
          )}
          {(!lendingKougu || lendingKougu.length === 0) && (!kouguWithNotes || kouguWithNotes.length === 0) && (!kouguAlerts || kouguAlerts.length === 0) && (
            <p className="text-xs text-muted-foreground">貸出中の工具はありません</p>
          )}
        </CardContent>
        )}
      </Card>

      {/* Pending Kyujitsu */}
      {pendingKyujitsu && pendingKyujitsu.length > 0 && (
        <Card className="mb-4 border-0 shadow-md overflow-hidden">
          <CardHeader className="pb-2 bg-orange-500 text-white rounded-t-lg">
            <CardTitle className="text-sm flex items-center gap-2 text-primary-foreground cursor-pointer" onClick={() => navigate("/kyujitsu")}>
              {renderToggle("kyujitsu")}
              <CalendarDays className="w-4 h-4" />
              休日申請 未承認 ({pendingKyujitsu.length}件)
            </CardTitle>
          </CardHeader>
          {!collapsed["kyujitsu"] && (
          <CardContent>
            <p className="text-[11px] text-muted-foreground mb-2">承認待ちの休日申請</p>
            <div className="flex flex-wrap gap-2">
              {pendingKyujitsu.map((k: any) => {
                const name = getDashboardPersonLabel(k.user_id);
                return (
                  <div key={k.id} className="flex items-center gap-2 p-2 rounded border border-warning/30 bg-warning/5 text-sm">
                    <div className="flex-1 min-w-0">
                      <div className="font-medium text-xs">{name}</div>
                      <div className="text-[10px] text-muted-foreground">📅 {k.holiday_date}{k.notes ? ` — ${k.notes}` : ""}</div>
                    </div>
                    <div className="flex gap-1 shrink-0">
                      {dashProcessed[k.id] ? (
                        <Badge className={`text-xs ${dashProcessed[k.id] === "承認済" ? "bg-green-600 text-white" : "bg-red-600 text-white"}`}>
                          {dashProcessed[k.id] === "承認済" ? "✅ 承認済" : "❌ 却下済"}
                        </Badge>
                      ) : (
                        <>
                          <Button size="sm" className="h-6 text-xs bg-green-600 hover:bg-green-700 text-white" onClick={() => handleKyujitsuStatus(k.id, "承認済")}>✅ 承認</Button>
                          <Button size="sm" className="h-6 text-xs bg-red-600 hover:bg-red-700 text-white" onClick={() => handleKyujitsuStatus(k.id, "却下")}>❌ 却下</Button>
                        </>
                      )}
                    </div>
                  </div>
                );
              })}
            </div>
          </CardContent>
          )}
        </Card>
      )}

      {/* Pending Maegari */}
      {pendingMaegari && pendingMaegari.length > 0 && (
        <Card className="mb-4 border-0 shadow-md overflow-hidden">
          <CardHeader className="pb-2 bg-rose-600 text-white rounded-t-lg">
            <CardTitle className="text-sm flex items-center gap-2 text-primary-foreground">
              {renderToggle("maegari")}
              <Banknote className="w-4 h-4" />
              前借金申請 未承認 ({pendingMaegari.length}件)
            </CardTitle>
          </CardHeader>
          {!collapsed["maegari"] && (
          <CardContent className="space-y-2">
            {pendingMaegari.map((m: any) => (
              <div key={m.id} className="flex items-center gap-3 p-2 rounded border border-accent/20 bg-accent/5 text-sm">
                <div className="flex-1 min-w-0">
                  <div className="font-medium">¥{Number(m.kingaku).toLocaleString()}</div>
                  <div className="text-xs text-muted-foreground">
                    {m.user_name} — {format(new Date(m.created_at), "yyyy/MM/dd HH:mm")}
                    {m.shudan && ` — ${m.shudan === "genkin" ? "現金" : "振込"}`}
                    {m.houhou && ` — ${m.houhou === "ikkatsu" ? "一括" : `${m.bunkatsu_kai || ""}回分割`}`}
                  </div>
                </div>
                <div className="flex gap-1 shrink-0">
                  {dashProcessed[m.id] ? (
                    <Badge className={`text-xs ${dashProcessed[m.id] === "承認済" ? "bg-green-600 text-white" : "bg-red-600 text-white"}`}>
                      {dashProcessed[m.id] === "承認済" ? "✅ 承認済" : "❌ 却下済"}
                    </Badge>
                  ) : (
                    <>
                      <Button size="sm" variant="default" className="h-7 text-xs" onClick={() => handleMaegariStatus(m.id, "承認")}>承認</Button>
                      <Button size="sm" variant="destructive" className="h-7 text-xs" onClick={() => handleMaegariStatus(m.id, "却下")}>却下</Button>
                    </>
                  )}
                </div>
              </div>
            ))}
          </CardContent>
          )}
        </Card>
      )}

      {/* Pending Yuukyuu */}
      {pendingYuukyuu && pendingYuukyuu.length > 0 && (
        <Card className="mb-4 border-0 shadow-md overflow-hidden">
          <CardHeader className="pb-2 bg-emerald-600 text-white rounded-t-lg">
            <CardTitle className="text-sm flex items-center gap-2 text-primary-foreground">
              {renderToggle("yuukyuu")}
              <CalendarDays className="w-4 h-4" />
              有給休暇申請 未承認 ({pendingYuukyuu.length}件)
            </CardTitle>
          </CardHeader>
          {!collapsed["yuukyuu"] && (
          <CardContent className="space-y-2">
            {pendingYuukyuu.map((y: any) => {
              const name = getDashboardPersonLabel(y.user_id);
              return (
                <div key={y.id} className="flex items-center gap-3 p-2 rounded border border-yellow-300/30 bg-yellow-50/50 dark:bg-yellow-900/10 text-sm">
                  <div className="flex-1 min-w-0">
                    <div className="font-medium">{name || `社員(${y.user_id?.slice(0, 6)})`}</div>
                    <div className="text-xs text-muted-foreground">
                      📅 {y.leave_date} ({y.days_used}日)
                      {y.reason && ` — ${y.reason}`}
                    </div>
                  </div>
                  <div className="flex gap-1 shrink-0">
                    {dashProcessed[y.id] ? (
                      <Badge className={`text-xs ${dashProcessed[y.id] === "承認済" ? "bg-green-600 text-white" : "bg-red-600 text-white"}`}>
                        {dashProcessed[y.id] === "承認済" ? "✅ 承認済" : "❌ 却下済"}
                      </Badge>
                    ) : (
                      <>
                        <Button size="sm" variant="default" className="h-7 text-xs" onClick={() => handleYuukyuuStatus(y.id, "承認済")}>承認</Button>
                        <Button size="sm" variant="destructive" className="h-7 text-xs" onClick={() => handleYuukyuuStatus(y.id, "却下")}>却下</Button>
                      </>
                    )}
                  </div>
                </div>
              );
            })}
          </CardContent>
          )}
        </Card>
      )}

      {dashAlerts.length > 0 && (
        <Card className="mb-6 border-0 shadow-md overflow-hidden">
          <CardHeader className="pb-2 bg-red-500 text-white rounded-t-lg">
            <CardTitle className="text-sm flex items-center gap-2 text-primary-foreground">
              {renderToggle("alerts")}
              <AlertTriangle className="w-4 h-4" />
              アラート通知 ({dashAlerts.length}件)
            </CardTitle>
          </CardHeader>
          {!collapsed["alerts"] && (
          <CardContent className="space-y-1.5">
            {dashAlerts.slice(0, 10).map((a, i) => {
              const Icon = a.icon;
              const canUpdate = !!a.updateTable && !!a.updateId && !!a.updateField;
              return (
                <div key={i} className={`flex items-start gap-3 p-2 rounded-md border ${
                  a.severity === "danger" ? "border-destructive bg-destructive/5" :
                  a.severity === "warning" ? "border-warning bg-warning/5" :
                  "border-primary/30 bg-primary/5"
                }`}>
                  <Icon className={`w-4 h-4 mt-0.5 shrink-0 ${
                    a.severity === "danger" ? "text-destructive" :
                    a.severity === "warning" ? "text-warning" : "text-primary"
                  }`} />
                  <div className="flex-1 min-w-0">
                    <div className="flex items-center gap-2">
                      <span className="text-xs font-bold">{a.label}</span>
                      <Badge variant={a.severity === "danger" ? "destructive" : a.severity === "warning" ? "outline" : "secondary"} className="text-[9px] px-1">
                        {a.daysLeft < 0 ? `${Math.abs(a.daysLeft)}日超過` : a.daysLeft === 0 ? "今日" : `あと${a.daysLeft}日`}
                      </Badge>
                    </div>
                    <p className="text-[11px] text-muted-foreground">{a.detail}</p>
                    {canUpdate && (
                      <div className="mt-1">
                        <Popover>
                          <PopoverTrigger asChild>
                            <Button variant="outline" size="sm" className="h-6 px-2 text-[10px] gap-1">
                              <CalendarIcon className="w-3 h-3" />
                              新しい日付を設定
                            </Button>
                          </PopoverTrigger>
                          <PopoverContent className="w-auto p-0 z-[100]" align="start">
                            <Calendar
                              mode="single"
                              selected={a.currentDate ? parseISO(a.currentDate) : undefined}
                              onSelect={(date) => {
                                if (date) handleAlertDateUpdate(a, date);
                              }}
                              className={cn("p-3 pointer-events-auto")}
                            />
                          </PopoverContent>
                        </Popover>
                      </div>
                    )}
                  </div>
                </div>
              );
            })}
            {dashAlerts.length > 10 && (
              <p className="text-xs text-muted-foreground text-center">他 {dashAlerts.length - 10}件...</p>
            )}
          </CardContent>
          )}
        </Card>
      )}

      {/* Pending Seikyu & Shiharai */}
      {((pendingSeikyu && pendingSeikyu.length > 0) || (pendingShiharai && pendingShiharai.length > 0) || (pendingChumon && pendingChumon.length > 0)) && (
        <Card className="mb-6 border-0 shadow-md overflow-hidden">
          <CardHeader className="pb-2 bg-slate-600 text-white rounded-t-lg">
            <CardTitle className="text-sm flex items-center gap-2 text-primary-foreground">
              {renderToggle("pending")}
              <FileText className="w-4 h-4 text-primary" />
              未処理書類
            </CardTitle>
          </CardHeader>
          {!collapsed["pending"] && (
          <CardContent>
          <div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
          {/* 請求書 */}
          {pendingSeikyu && pendingSeikyu.length > 0 && (
            <Card className="border border-success/30">
              <CardHeader className="pb-2">
                <CardTitle className="text-sm flex items-center gap-2">
                  <FileText className="w-4 h-4 text-success" />
                  請求書 未処理 ({pendingSeikyu.length}件)
                </CardTitle>
              </CardHeader>
              <CardContent className="space-y-1.5">
                {pendingSeikyu.map((s: any) => (
                  <div key={s.id} className="flex items-center gap-2 p-2 rounded-md border bg-card hover:bg-muted/50 cursor-pointer" onClick={() => navigate(`/seikyu/${s.id}`)}>
                    <div className="flex-1 min-w-0">
                      <div className="flex items-center gap-2">
                        <span className="text-xs font-bold">{s.invoice_no || "—"}</span>
                        <span className="text-[11px] text-muted-foreground truncate">{(s.client as any)?.company_name || ""}</span>
                      </div>
                      <p className="text-[11px] text-muted-foreground">
                        {s.invoice_date || "日付未定"} ・ ¥{(s.total_amount || 0).toLocaleString()}
                      </p>
                    </div>
                    <Select value={s.status} onValueChange={(v) => { handlePendingStatusChange("seikyu", s.id, v); }}>
                      <SelectTrigger className="h-7 w-[90px] text-[11px]" onClick={(e) => e.stopPropagation()}>
                        <SelectValue />
                      </SelectTrigger>
                      <SelectContent>
                        {pendingStatusOptions.map(st => (
                          <SelectItem key={st} value={st} className="text-xs">{st}</SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </div>
                ))}
              </CardContent>
            </Card>
          )}

          {/* 支払通知書 */}
          {pendingShiharai && pendingShiharai.length > 0 && (
            <Card className="border border-primary/30">
              <CardHeader className="pb-2">
                <CardTitle className="text-sm flex items-center gap-2">
                  <CreditCard className="w-4 h-4 text-primary" />
                  支払通知書 未処理 ({pendingShiharai.length}件)
                </CardTitle>
              </CardHeader>
              <CardContent className="space-y-1.5">
                {pendingShiharai.map((s: any) => (
                  <div key={s.id} className="flex items-center gap-2 p-2 rounded-md border bg-card hover:bg-muted/50 cursor-pointer" onClick={() => navigate(`/shiharai/${s.id}`)}>
                    <div className="flex-1 min-w-0">
                      <div className="flex items-center gap-2">
                        <span className="text-xs font-bold">{s.notice_no || "—"}</span>
                        <span className="text-[11px] text-muted-foreground truncate">{(s.client as any)?.company_name || ""}</span>
                      </div>
                      <p className="text-[11px] text-muted-foreground">
                        支払日: {s.payment_date || "未定"} ・ ¥{(s.transfer_amount || 0).toLocaleString()}
                      </p>
                    </div>
                    <Select value={s.status} onValueChange={(v) => { handlePendingStatusChange("shiharai", s.id, v); }}>
                      <SelectTrigger className="h-7 w-[90px] text-[11px]" onClick={(e) => e.stopPropagation()}>
                        <SelectValue />
                      </SelectTrigger>
                      <SelectContent>
                        {pendingStatusOptions.map(st => (
                          <SelectItem key={st} value={st} className="text-xs">{st}</SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </div>
                ))}
              </CardContent>
            </Card>
          )}

          {/* 注文書 */}
          {pendingChumon && pendingChumon.length > 0 && (
            <Card className="border border-warning/30">
              <CardHeader className="pb-2">
                <CardTitle className="text-sm flex items-center gap-2">
                  <ClipboardList className="w-4 h-4 text-warning" />
                  注文書 未処理 ({pendingChumon.length}件)
                </CardTitle>
              </CardHeader>
              <CardContent className="space-y-1.5">
                {pendingChumon.map((s: any) => (
                  <div key={s.id} className="flex items-center gap-2 p-2 rounded-md border bg-card hover:bg-muted/50 cursor-pointer" onClick={() => navigate(`/chumon/${s.id}`)}>
                    <div className="flex-1 min-w-0">
                      <div className="flex items-center gap-2">
                        <span className="text-xs font-bold">{s.order_no || "—"}</span>
                        <span className="text-[11px] text-muted-foreground truncate">{(s.client as any)?.company_name || ""}</span>
                      </div>
                      <p className="text-[11px] text-muted-foreground">
                        {s.order_date || "日付未定"} ・ ¥{(s.total_amount || 0).toLocaleString()}
                      </p>
                    </div>
                    <Select value={s.status} onValueChange={(v) => { handlePendingStatusChange("chumon" as any, s.id, v); }}>
                      <SelectTrigger className="h-7 w-[90px] text-[11px]" onClick={(e) => e.stopPropagation()}>
                        <SelectValue />
                      </SelectTrigger>
                      <SelectContent>
                        {pendingStatusOptions.map(st => (
                          <SelectItem key={st} value={st} className="text-xs">{st}</SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </div>
                ))}
              </CardContent>
            </Card>
          )}
        </div>
          </CardContent>
          )}
        </Card>
      )}

      {/* Pending Chumon - separate row if alone */}

      {/* Monthly Finance Summary */}
      {isAdmin && (<>
      <SectionHeader icon={Banknote} title="月別 収支サマリー">
        {renderToggle("finance")}
      </SectionHeader>
      {!collapsed["finance"] && <LazyWidget minHeight={300}><MonthlyFinanceSummary /></LazyWidget>}
      {!collapsed["finance"] && (
        <div className="flex justify-end mt-2">
          <Button variant="outline" size="sm" className="text-xs gap-1" onClick={async () => {
            const ym = format(new Date(), "yyyy-MM");
            const { generateMonthlyReportPdf } = await import("@/lib/monthly-report-pdf");
            generateMonthlyReportPdf(ym);
          }}>
            📄 月次レポート出力 (PDF)
          </Button>
        </div>
      )}
      </>)}

      {/* Shikudai Score Panel */}
      {isAdmin && (<>
      <SectionHeader icon={ClipboardList} title="本日の宿題スコア">
        {renderToggle("shikudai")}
      </SectionHeader>
      {!collapsed["shikudai"] && <LazyWidget minHeight={200}><ShikudaiScorePanel /></LazyWidget>}
      </>)}

      {/* Unified Calendar */}
      <SectionHeader icon={CalendarDays} title="統合カレンダー">
        {renderToggle("calendar")}
      </SectionHeader>
      {!collapsed["calendar"] && <LazyWidget minHeight={400}><UnifiedCalendar /></LazyWidget>}

      {/* Genba Profit Summary */}
      {isAdmin && (<>
      <SectionHeader icon={Building2} title="現場別 目標利益">
        {renderToggle("genbaProfit")}
      </SectionHeader>
      {!collapsed["genbaProfit"] && <LazyWidget minHeight={300}><GenbaProfitSummary /></LazyWidget>}
      {!collapsed["genbaProfit"] && <div className="mt-4"><LazyWidget minHeight={300}><GenbaProfitChart /></LazyWidget></div>}

      {/* Monthly Zairyo Summary */}
      <SectionHeader icon={Wrench} title="月別 材料費">
        {renderToggle("zairyo")}
      </SectionHeader>
      {!collapsed["zairyo"] && <LazyWidget minHeight={300}><MonthlyZairyoSummary /></LazyWidget>}

      {/* Company Settings */}
      <SectionHeader icon={Building2} title="会社情報">
        {renderToggle("company")}
      </SectionHeader>
      {!collapsed["company"] && <LazyWidget minHeight={300}><CompanySettingsEditor /></LazyWidget>}
      </>)}

      {/* Genba selection dialog */}
      <Dialog open={showGenbaSelect} onOpenChange={(open) => { setShowGenbaSelect(open); if (!open) setGenbaSearchQuery(""); }}>
        <DialogContent className="max-w-sm">
          <DialogHeader>
            <DialogTitle>現場を選択してから撮影</DialogTitle>
          </DialogHeader>
          <div className="space-y-3 py-2">
            <div className="relative">
              <Search className="absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted-foreground" />
              <Input
                value={genbaSearchQuery}
                onChange={(e) => setGenbaSearchQuery(e.target.value)}
                placeholder="現場番号 or 現場名で検索"
                className="h-9 text-sm pl-8"
                autoFocus
              />
            </div>
            <div className="max-h-[50vh] overflow-y-auto space-y-1">
              {(activeGenba || [])
                .filter((g: any) => {
                  if (!genbaSearchQuery.trim()) return true;
                  const q = genbaSearchQuery.trim().toLowerCase();
                  return (
                    g.genba_no?.toLowerCase().includes(q) ||
                    g.project_name?.toLowerCase().includes(q) ||
                    g.branch?.toLowerCase().includes(q) ||
                    g.manager_name?.toLowerCase().includes(q) ||
                    (g.search_keywords || "").toLowerCase().includes(q)
                  );
                })
                .map((g: any) => (
                  <Button
                    key={g.id}
                    variant={selectedGenbaId === g.id ? "default" : "ghost"}
                    size="sm"
                    className="w-full justify-start h-auto py-2 text-xs"
                    onClick={() => {
                      setShowGenbaSelect(false);
                      setGenbaSearchQuery("");
                      navigate(`/genba/${g.id}?denpyo=1`);
                    }}
                  >
                    <span className="font-mono mr-1.5">{g.genba_no}</span>
                    <span className="truncate">{g.project_name}</span>
                    {g.branch && <span className="ml-auto text-muted-foreground shrink-0">({g.branch})</span>}
                  </Button>
                ))}
            </div>
          </div>
        </DialogContent>
      </Dialog>
    </AppLayout>
  );
}
