'use client';

import { RouteGuard } from '@/components/auth/Guard';
import { useEffect, useMemo, useState } from 'react';
import { Search, Plus, Lightbulb, ArrowUp, ArrowDown, ChevronDown, ChevronRight, FolderOpen, Layers } from 'lucide-react';
import { useRequirementStore } from '@/stores/useRequirementStore';
import { useProductStore } from '@/stores/useProductStore';
import { useDevTaskStore } from '@/stores/useDevTaskStore';
import { useAuthStore } from '@/stores/useAuthStore';
import { flattenProjects, flattenVersions } from '@/lib/derive';
import { REQ_STATUS_LABEL, REQ_STATUS_COLOR, SOURCE_TYPE_LABEL } from '@/lib/requirement';
import type { Requirement, RequirementStatus, SourceType } from '@/lib/requirement';
import { buildRequirementDevStatusMap, canEditRequirement, canCloseRequirement, REQ_DEV_STATUS_LABEL, REQ_DEV_STATUS_COLOR } from '@/lib/linkage-engine';
import { buildRequirementScopeTree, filterRequirementScopeTreeByKeyword, filterRequirementsByScope, type RequirementProductScopeNode, type RequirementScopeSelection } from '@/lib/requirement-scope';
import { sortRequirementsByCreatedAt, type RequirementDateSort } from '@/lib/requirement-sort';
import {
  REQUIREMENT_TABLE_BADGE_CLASS,
  REQUIREMENT_TABLE_CLASS,
  REQUIREMENT_TABLE_COLUMN_WIDTHS,
  REQUIREMENT_TABLE_CONTAINER_CLASS,
  REQUIREMENT_TABLE_HEADER_CELL_CLASS,
  REQUIREMENT_TABLE_NOWRAP_CELL_CLASS,
  REQUIREMENT_TABLE_SMALL_BADGE_CLASS,
  getRequirementTableTextClass,
} from '@/lib/requirement-table-layout';
import { getRequirementVersionSelectionPatch } from '@/lib/requirement-version-link';
import { Pagination } from '@/components/Pagination';
import { RequirementModal } from '@/components/requirement/RequirementModal';
import { RequirementDetail } from '@/components/requirement/RequirementDetail';
import { DictDrawer, SourceDrawer } from '@/components/requirement/DictDrawer';
import { FilterSelect } from '@/components/FilterSelect';
import { buildV22RequirementQuery } from '@/lib/requirement-v22-query';
import { loadV22RequirementsPage } from '@/lib/v22-api';

const PRIORITY_COLORS: Record<string, string> = {
  P0: 'bg-red-500/10 text-red-600',
  P1: 'bg-orange-500/10 text-orange-600',
  P2: 'bg-blue-500/10 text-blue-600',
  P3: 'bg-zinc-100 text-zinc-600',
  P4: 'bg-zinc-100 text-zinc-500',
};

const STATUS_TABS: { key: string; label: string }[] = [
  { key: 'all', label: '全部' },
  { key: 'pending_review', label: '待评审' },
  { key: 'adopted', label: '已采纳' },
  { key: 'rejected', label: '已拒绝' },
  { key: 'developing', label: '开发中' },
  { key: 'dev_completed', label: '已完成' },
  { key: 'released', label: '已上线' },
  { key: 'closed', label: '已关闭' },
];

export default function RequirementsPage() {
  return (
    <RouteGuard permission="requirement:view">
      <RequirementsPageContent />
    </RouteGuard>
  );
}

function RequirementProductNode({
  product,
  selectedScope,
  onSelect,
}: {
  product: RequirementProductScopeNode;
  selectedScope: RequirementScopeSelection;
  onSelect: (scope: RequirementScopeSelection) => void;
}) {
  const [expanded, setExpanded] = useState(true);
  const active = selectedScope.type === 'product' && selectedScope.productId === product.id;

  return (
    <div className="mb-0.5">
      <div className="flex items-center gap-1">
        <button
          type="button"
          onClick={() => setExpanded((value) => !value)}
          className="flex h-7 w-6 shrink-0 items-center justify-center rounded-md text-[var(--ink-muted)] hover:bg-[var(--bg-subtle)]"
          aria-label={expanded ? '收起产品' : '展开产品'}
        >
          {expanded ? <ChevronDown className="h-3 w-3" /> : <ChevronRight className="h-3 w-3" />}
        </button>
        <button
          type="button"
          onClick={() => onSelect({ type: 'product', productId: product.id })}
          className={`flex min-w-0 flex-1 items-center gap-2 rounded-lg px-2 py-1.5 text-[12px] transition-colors ${
            active
              ? 'bg-[var(--accent-soft)] font-medium text-[var(--accent)]'
              : 'text-[var(--ink-soft)] hover:bg-[var(--bg-subtle)]'
          }`}
        >
          <span className="min-w-0 flex-1 truncate text-left">{product.name}</span>
          <ScopeSignals count={product.count} />
        </button>
      </div>
      {expanded && (
        <div className="ml-7 mt-0.5 space-y-0.5">
          {product.projects.map((project) => (
            <RequirementProjectNode
              key={project.id}
              project={project}
              selectedScope={selectedScope}
              onSelect={onSelect}
            />
          ))}
        </div>
      )}
    </div>
  );
}

function RequirementProjectNode({
  project,
  selectedScope,
  onSelect,
}: {
  project: RequirementProductScopeNode['projects'][number];
  selectedScope: RequirementScopeSelection;
  onSelect: (scope: RequirementScopeSelection) => void;
}) {
  const active = selectedScope.type === 'project' && selectedScope.projectId === project.id;

  return (
    <button
      type="button"
      onClick={() => onSelect({ type: 'project', projectId: project.id })}
      className={`flex w-full min-w-0 items-center gap-2 rounded-lg px-2 py-1.5 text-[12px] transition-colors ${
        active
          ? 'bg-[var(--accent-soft)] font-medium text-[var(--accent)]'
          : 'text-[var(--ink-soft)] hover:bg-[var(--bg-subtle)]'
      }`}
    >
      <FolderOpen className="h-3.5 w-3.5 shrink-0 text-[var(--ink-muted)]" />
      <span className="min-w-0 flex-1 truncate text-left">{project.name}</span>
      <ScopeSignals count={project.count} compact />
    </button>
  );
}

function ScopeSignals({ count, compact = false }: { count: RequirementProductScopeNode['count']; compact?: boolean }) {
  const pendingReview = count.byStatus.pending_review ?? 0;
  const active = (count.byStatus.developing ?? 0) + (count.byStatus.testing ?? 0);

  return (
    <span className="flex shrink-0 items-center gap-1">
      {!compact && <ScopeSignal title="待评审" label="评" count={pendingReview} tone="amber" />}
      {!compact && <ScopeSignal title="执行中" label="进" count={active} tone="blue" />}
      <ScopeCount count={count.total} />
    </span>
  );
}

function ScopeSignal({ title, label, count, tone }: { title: string; label: string; count: number; tone: 'amber' | 'blue' }) {
  if (count <= 0) return null;
  const toneClass = tone === 'amber' ? 'bg-amber-50 text-amber-700' : 'bg-blue-50 text-blue-700';
  return (
    <span title={title} className={`rounded px-1.5 py-0.5 text-[10px] font-medium tabular-nums ${toneClass}`}>
      {label}{count}
    </span>
  );
}

function ScopeCount({ count }: { count: number }) {
  return (
    <span className="rounded bg-[var(--bg-subtle)] px-1.5 py-0.5 text-[10px] font-medium tabular-nums text-[var(--ink-muted)]">
      {count}
    </span>
  );
}

function RequirementsPageContent() {
  const {
    requirements, fetchRequirements, createRequirement, updateRequirement, deleteRequirement,
    sourceTargets, types, platforms,
    addSourceTarget, updateSourceTarget, deleteSourceTarget,
    addType, updateType, deleteType,
    addPlatform, updatePlatform, deletePlatform,
    loaded: requirementsLoaded,
  } = useRequirementStore();
  const { overview, fetchOverview } = useProductStore();
  const { tasks: devTasks, fetchTasks: fetchDevTasks } = useDevTaskStore();
  const user = useAuthStore((s) => s.user);
  const currentUserName = user?.name || '系统';
  const allProjects = useMemo(() => flattenProjects(overview), [overview]);
  const allVersions = useMemo(() => flattenVersions(overview), [overview]);
  const requirementDevStatusMap = useMemo(() => buildRequirementDevStatusMap(devTasks), [devTasks]);
  const devTasksByRequirement = useMemo(() => {
    const map = new Map<string, typeof devTasks>();
    for (const task of devTasks) {
      if (!task.requirementId) continue;
      const items = map.get(task.requirementId) ?? [];
      items.push(task);
      map.set(task.requirementId, items);
    }
    return map;
  }, [devTasks]);

  const [selectedScope, setSelectedScope] = useState<RequirementScopeSelection>({ type: 'all' });
  const [scopeSearch, setScopeSearch] = useState('');
  const [search, setSearch] = useState('');
  const [statusFilter, setStatusFilter] = useState('all');
  const [priorityFilter, setPriorityFilter] = useState('all');
  const [typeFilter, setTypeFilter] = useState('all');
  const [versionFilter, setVersionFilter] = useState('all');

  const [showModal, setShowModal] = useState(false);
  const [editingReq, setEditingReq] = useState<Requirement | null>(null);
  const [viewingReq, setViewingReq] = useState<Requirement | null>(null);
  const [drawerType, setDrawerType] = useState<null | 'source' | 'type' | 'platform'>(null);
  const [rejectingReq, setRejectingReq] = useState<Requirement | null>(null);
  const [rejectReason, setRejectReason] = useState('');
  const [dateSort, setDateSort] = useState<RequirementDateSort>('desc');
  const [page, setPage] = useState(1);
  const [pageSize, setPageSizeState] = useState(20);
  const [autoScopeSelected, setAutoScopeSelected] = useState(false);
  const [v22Requirements, setV22Requirements] = useState<Requirement[]>([]);
  const [v22NextCursor, setV22NextCursor] = useState<string | undefined>();
  const [v22CursorByPage, setV22CursorByPage] = useState<Record<number, string | undefined>>({ 1: undefined });
  const [v22RequirementsLoading, setV22RequirementsLoading] = useState(false);
  const [v22RequirementsFailed, setV22RequirementsFailed] = useState(false);

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

  const selectedScopeKey = selectedScope.type === 'all'
    ? 'all'
    : selectedScope.type === 'product'
      ? `product:${selectedScope.productId}`
      : `project:${selectedScope.projectId}`;

  useEffect(() => {
    setVersionFilter('all');
  }, [selectedScopeKey]);

  useEffect(() => {
    if (autoScopeSelected || selectedScope.type !== 'all') return;
    const firstProductId = overview[0]?.id;
    if (!firstProductId) return;
    setSelectedScope({ type: 'product', productId: firstProductId });
    setAutoScopeSelected(true);
  }, [autoScopeSelected, overview, selectedScope.type]);

  const scopeTree = useMemo(() => buildRequirementScopeTree(overview, requirements), [overview, requirements]);
  const searchedScopeTree = useMemo(() => filterRequirementScopeTreeByKeyword(scopeTree, scopeSearch), [scopeTree, scopeSearch]);
  const scopedRequirements = useMemo(() => filterRequirementsByScope(requirements, selectedScope), [requirements, selectedScope]);
  const scopedVersions = useMemo(() => {
    if (selectedScope.type === 'product') return allVersions.filter((v) => v.productId === selectedScope.productId);
    if (selectedScope.type === 'project') return allVersions.filter((v) => v.projectId === selectedScope.projectId);
    return allVersions;
  }, [allVersions, selectedScope]);

  const filterResetKey = useMemo(() => JSON.stringify({
    selectedScopeKey,
    search,
    statusFilter,
    priorityFilter,
    typeFilter,
    versionFilter,
    dateSort,
  }), [dateSort, priorityFilter, search, selectedScopeKey, statusFilter, typeFilter, versionFilter]);

  useEffect(() => {
    setPage(1);
    setV22CursorByPage({ 1: undefined });
    setV22Requirements([]);
    setV22NextCursor(undefined);
  }, [filterResetKey]);

  const v22Cursor = v22CursorByPage[page];
  const v22RequirementQuery = useMemo(() => buildV22RequirementQuery({
    selectedScope,
    projects: allProjects.map((project) => ({ id: project.id, productId: project.productId })),
    statusFilter,
    priorityFilter,
    typeFilter,
    versionFilter,
    search,
    dateSort,
    limit: pageSize,
    cursor: v22Cursor,
  }), [
    allProjects,
    dateSort,
    pageSize,
    priorityFilter,
    search,
    selectedScope,
    statusFilter,
    typeFilter,
    versionFilter,
    v22Cursor,
  ]);

  useEffect(() => {
    if (v22RequirementQuery && !v22RequirementsFailed) return;
    fetchRequirements();
    fetchDevTasks();
  }, [fetchDevTasks, fetchRequirements, v22RequirementQuery, v22RequirementsFailed]);

  useEffect(() => {
    setV22RequirementsFailed(false);
  }, [filterResetKey, pageSize]);

  useEffect(() => {
    if (!v22RequirementQuery) {
      setV22Requirements([]);
      setV22NextCursor(undefined);
      return;
    }

    let cancelled = false;
    setV22RequirementsLoading(true);
    loadV22RequirementsPage(v22RequirementQuery)
      .then((result) => {
        if (cancelled) return;
        setV22Requirements(result.items);
        setV22NextCursor(result.nextCursor);
        if (result.nextCursor) {
          setV22CursorByPage((current) => (
            current[page + 1] === result.nextCursor
              ? current
              : { ...current, [page + 1]: result.nextCursor }
          ));
        }
      })
      .catch(() => {
        if (cancelled) return;
        setV22Requirements([]);
        setV22NextCursor(undefined);
        setV22RequirementsFailed(true);
        fetchRequirements();
        fetchDevTasks();
      })
      .finally(() => {
        if (!cancelled) setV22RequirementsLoading(false);
      });

    return () => {
      cancelled = true;
    };
  }, [fetchDevTasks, fetchRequirements, page, v22RequirementQuery]);

  const selectedScopeTitle = useMemo(() => {
    if (selectedScope.type === 'product') {
      return overview.find((product) => product.id === selectedScope.productId)?.name ?? '产品需求';
    }
    if (selectedScope.type === 'project') {
      return allProjects.find((project) => project.id === selectedScope.projectId)?.name ?? '项目需求';
    }
    return '全部需求';
  }, [allProjects, overview, selectedScope]);

  const selectedScopeMeta = useMemo(() => {
    if (selectedScope.type === 'product') return '产品下全部项目';
    if (selectedScope.type === 'project') {
      const project = allProjects.find((item) => item.id === selectedScope.projectId);
      return project ? `${project.productName} / 项目` : '项目';
    }
    return '所有产品与项目';
  }, [allProjects, selectedScope]);

  // Resolve version name from overview
  const resolveVersionName = (versionId?: string): string => {
    if (!versionId) return '-';
    for (const product of overview) {
      const version = product.versions?.find((v: any) => v.id === versionId);
      if (version) return version.name;
    }
    return '-';
  };

  const filtered = useMemo(() => {
    let list = [...scopedRequirements];

    // search filter
    if (search) {
      const q = search.toLowerCase();
      list = list.filter(
        (r) => r.code.toLowerCase().includes(q) || r.title.toLowerCase().includes(q),
      );
    }

    // status filter
    if (statusFilter !== 'all') {
      list = statusFilter === 'dev_completed'
        ? list.filter((r) => requirementDevStatusMap.get(r.id) === 'completed')
        : list.filter((r) => r.status === statusFilter);
    }

    // priority filter
    if (priorityFilter !== 'all') {
      list = list.filter((r) => r.priority === priorityFilter);
    }

    // type filter
    if (typeFilter !== 'all') {
      list = list.filter((r) => r.typeId === typeFilter);
    }
    if (versionFilter !== 'all') {
      list = list.filter((r) => r.versionId === versionFilter);
    }

    list = sortRequirementsByCreatedAt(list, dateSort);

    return list;
  }, [scopedRequirements, search, statusFilter, priorityFilter, typeFilter, versionFilter, dateSort, requirementDevStatusMap]);

  const appDataRequirementIds = useMemo(() => new Set(requirements.map((item) => item.id)), [requirements]);
  const usingV22Requirements = Boolean(v22RequirementQuery) && !v22RequirementsFailed;
  const appTotalPages = Math.max(1, Math.ceil(filtered.length / pageSize));
  const appPage = Math.min(page, appTotalPages);
  const appPaged = filtered.slice((appPage - 1) * pageSize, appPage * pageSize);
  const displayedRequirements = usingV22Requirements ? v22Requirements : appPaged;
  const total = usingV22Requirements
    ? (page - 1) * pageSize + v22Requirements.length + (v22NextCursor ? 1 : 0)
    : filtered.length;
  const displayPage = usingV22Requirements ? page : appPage;
  const displayedScopeCount = usingV22Requirements ? total : scopedRequirements.length;
  const canMutateRequirement = (req: Requirement) => requirementsLoaded && appDataRequirementIds.has(req.id);
  const handlePageChange = (nextPage: number) => {
    if (usingV22Requirements && nextPage > page && !v22CursorByPage[nextPage]) return;
    setPage(nextPage);
  };
  const setPageSize = (size: number) => {
    setPageSizeState(size);
    setPage(1);
    setV22CursorByPage({ 1: undefined });
  };

  const handleEdit = (req: Requirement) => {
    if (!canMutateRequirement(req)) return;
    setViewingReq(null);
    setEditingReq(req);
    setShowModal(true);
  };

  const handleRowClick = (req: Requirement) => {
    setViewingReq(req);
  };

  const handleCreate = async () => {
    await fetchRequirements();
    setEditingReq(null);
    setShowModal(true);
  };

  const handleSelectScope = (scope: RequirementScopeSelection) => {
    setAutoScopeSelected(true);
    setSelectedScope(scope);
    if (scope.type === 'all') {
      fetchRequirements();
      fetchDevTasks();
    }
  };

  return (
    <div className="flex h-full overflow-hidden bg-[var(--bg)]">
      <aside className="flex w-72 shrink-0 flex-col border-r border-[var(--line)] bg-[var(--bg-card)]">
        <div className="flex h-14 shrink-0 items-center justify-between border-b border-[var(--line)] px-4">
          <div>
            <h1 className="text-[14px] font-semibold text-[var(--ink)]">需求池</h1>
            <p className="mt-0.5 text-[11px] text-[var(--ink-muted)]">按产品 / 项目查看</p>
          </div>
          <span className="rounded-md bg-[var(--bg-subtle)] px-1.5 py-0.5 text-[11px] font-medium tabular-nums text-[var(--ink-soft)]">
            {requirements.length}
          </span>
        </div>
        <div className="shrink-0 border-b border-[var(--line)] px-3 py-3">
          <div className="relative">
            <Search className="pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-[var(--ink-muted)]" strokeWidth={2} />
            <input
              value={scopeSearch}
              onChange={(event) => setScopeSearch(event.target.value)}
              placeholder="搜索产品或项目"
              aria-label="搜索产品或项目"
              className="h-8 w-full rounded-lg border border-[var(--line)] bg-[var(--bg)] pl-8 pr-3 text-[12px] text-[var(--ink)] placeholder:text-[var(--ink-muted)] focus:border-[var(--accent)] focus:outline-none focus:ring-2 focus:ring-[var(--accent-ring)]"
            />
          </div>
        </div>
        <div className="flex-1 overflow-y-auto p-2">
          <button
            onClick={() => handleSelectScope({ type: 'all' })}
            className={`mb-1 flex w-full items-center gap-2 rounded-lg px-3 py-2 text-[12px] transition-colors ${
              selectedScope.type === 'all'
                ? 'bg-[var(--accent-soft)] font-medium text-[var(--accent)]'
                : 'text-[var(--ink-soft)] hover:bg-[var(--bg-subtle)]'
            }`}
          >
            <Layers className="h-3.5 w-3.5 shrink-0" />
            <span className="flex-1 text-left">全部需求</span>
            <ScopeCount count={requirements.length} />
          </button>
          {searchedScopeTree.map((product) => (
            <RequirementProductNode
              key={product.id}
              product={product}
              selectedScope={selectedScope}
              onSelect={handleSelectScope}
            />
          ))}
          {searchedScopeTree.length === 0 && scopeSearch.trim() && (
            <div className="mt-3 rounded-lg border border-dashed border-[var(--line)] px-3 py-4 text-center text-[12px] text-[var(--ink-muted)]">
              没有匹配的产品或项目
            </div>
          )}
        </div>
      </aside>

      <main className="min-w-0 flex-1 flex flex-col overflow-hidden">
      {/* Header */}
      <header className="flex h-14 shrink-0 items-center justify-between border-b border-[var(--line)] bg-[var(--bg-card)] px-5">
        <div className="min-w-0">
          <div className="flex items-center gap-2.5">
            <h2 className="truncate text-[15px] font-semibold tracking-tight text-[var(--ink)]">{selectedScopeTitle}</h2>
            <span className="rounded-md bg-[var(--bg-subtle)] px-1.5 py-0.5 text-[11px] font-medium tabular-nums text-[var(--ink-soft)]">
              {displayedScopeCount}
            </span>
          </div>
          <p className="mt-0.5 text-[11px] text-[var(--ink-muted)]">{selectedScopeMeta}</p>
        </div>
        <div className="flex items-center gap-2">
          <button
            onClick={() => { fetchRequirements(); setDrawerType('source'); }}
            className="flex h-8 items-center gap-1.5 rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 text-[13px] font-medium text-[var(--ink-soft)] hover:border-[var(--accent)] hover:text-[var(--accent)] transition-colors"
          >
            <Lightbulb className="h-3.5 w-3.5" strokeWidth={2} />
            来源管理
          </button>
          <button
            onClick={handleCreate}
            className="flex h-8 items-center gap-1.5 rounded-lg bg-[var(--accent)] px-3 text-[13px] font-medium text-white shadow-[var(--shadow-sm)] hover:bg-[var(--accent-hover)] transition-colors"
          >
            <Plus className="h-3.5 w-3.5" strokeWidth={2} />
            新建需求
          </button>
        </div>
      </header>

      {/* Filters */}
      <div className="flex shrink-0 flex-wrap items-center gap-3 border-b border-[var(--line)] bg-[var(--bg-card)] px-5 py-3">
        <div className="relative">
          <Search className="pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-[var(--ink-muted)]" strokeWidth={2} />
          <input
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            placeholder="搜索编号或标题"
            className="h-8 w-64 rounded-lg border border-[var(--line)] bg-[var(--bg)] pl-8 pr-3 text-[13px] text-[var(--ink)] placeholder:text-[var(--ink-muted)] focus:border-[var(--accent)] focus:outline-none focus:ring-2 focus:ring-[var(--accent-ring)]"
          />
        </div>

        {/* Status tabs */}
        <div className="flex flex-wrap gap-1">
          {STATUS_TABS.map((tab) => (
            <button
              key={tab.key}
              onClick={() => setStatusFilter(tab.key)}
              className={`h-8 rounded-lg px-3 text-[12px] transition-colors ${
                statusFilter === tab.key
                  ? 'bg-[var(--accent)] text-white'
                  : 'border border-[var(--line)] bg-[var(--bg-card)] text-[var(--ink-soft)] hover:border-[var(--accent)] hover:text-[var(--accent)]'
              }`}
            >
              {tab.label}
            </button>
          ))}
        </div>

        {/* Priority dropdown */}
        <FilterSelect
          value={priorityFilter}
          onChange={setPriorityFilter}
          options={['P0', 'P1', 'P2', 'P3', 'P4'].map((p) => ({ value: p, label: p }))}
          placeholder="全部优先级"
          allLabel="全部优先级"
        />

        {/* Type dropdown */}
        <FilterSelect
          value={typeFilter}
          onChange={setTypeFilter}
          options={types.map((t) => ({ value: t.id, label: t.name }))}
          placeholder="全部类型"
          allLabel="全部类型"
        />

        {/* Version dropdown */}
        <FilterSelect
          value={versionFilter}
          onChange={setVersionFilter}
          options={scopedVersions.map((v) => ({ value: v.id, label: v.name }))}
          placeholder="全部版本"
          allLabel="全部版本"
        />
      </div>

      {/* Content */}
      <div className="flex-1 overflow-y-auto bg-[var(--bg)]">
        <div className="px-5 py-4">
          {displayedRequirements.length === 0 && !v22RequirementsLoading ? (
            <div className="rounded-2xl border border-dashed border-[var(--line)] bg-[var(--bg-card)] py-20 text-center">
              <p className="text-[13px] font-medium text-[var(--ink-soft)]">没有找到匹配的需求</p>
              <p className="mt-1.5 text-[12px] text-[var(--ink-muted)]">尝试调整筛选条件</p>
            </div>
          ) : (
            <>
              <div className={REQUIREMENT_TABLE_CONTAINER_CLASS}>
                <table className={REQUIREMENT_TABLE_CLASS}>
                  <colgroup>
                    {REQUIREMENT_TABLE_COLUMN_WIDTHS.map((width, index) => (
                      <col key={index} style={{ width: `${width}%` }} />
                    ))}
                  </colgroup>
                  <thead className="sticky top-0 z-10 bg-[var(--bg-subtle)]">
                    <tr className="border-b border-[var(--line)] bg-[var(--bg-subtle)]">
                      <th className={REQUIREMENT_TABLE_HEADER_CELL_CLASS}>需求编号</th>
                      <th className={REQUIREMENT_TABLE_HEADER_CELL_CLASS}>需求概述</th>
                      <th className={REQUIREMENT_TABLE_HEADER_CELL_CLASS}>需求来源</th>
                      <th className={REQUIREMENT_TABLE_HEADER_CELL_CLASS}>所属项目</th>
                      <th className={REQUIREMENT_TABLE_HEADER_CELL_CLASS}>需求类型</th>
                      <th className={REQUIREMENT_TABLE_HEADER_CELL_CLASS}>业务状态</th>
                      <th className={REQUIREMENT_TABLE_HEADER_CELL_CLASS}>优先级</th>
                      <th className={REQUIREMENT_TABLE_HEADER_CELL_CLASS}>所属版本</th>
                      <th className={REQUIREMENT_TABLE_HEADER_CELL_CLASS}>实际进度</th>
                      <th className={REQUIREMENT_TABLE_HEADER_CELL_CLASS}>录入人员</th>
                      <th
                        className={`${REQUIREMENT_TABLE_HEADER_CELL_CLASS} cursor-pointer select-none transition-colors hover:text-[var(--ink-soft)]`}
                        onClick={() => setDateSort(dateSort === 'desc' ? 'asc' : 'desc')}
                      >
                        <span className="inline-flex items-center gap-1">
                          录入日期
                          {dateSort === 'desc' ? <ArrowDown className="h-3 w-3" /> : <ArrowUp className="h-3 w-3" />}
                        </span>
                      </th>
                      <th className={`${REQUIREMENT_TABLE_HEADER_CELL_CLASS} text-right`}>操作</th>
                    </tr>
                  </thead>
                  <tbody>
                    {displayedRequirements.map((req) => (
                      <tr
                        key={req.id}
                        onClick={() => handleRowClick(req)}
                        className="border-b border-[var(--line-soft)] last:border-0 cursor-pointer transition-colors hover:bg-[var(--bg-subtle)]"
                      >
                        {/* 需求编号 */}
                        <td className="px-4 py-3 whitespace-nowrap">
                          <span className="font-medium text-[var(--ink)]">{req.code}</span>
                        </td>

                        {/* 需求概述 */}
                        <td className="px-4 py-3">
                          <span className="block max-w-[200px] truncate text-[var(--ink)]">{req.title}</span>
                        </td>

                        {/* 需求来源 */}
                        <td className="px-4 py-3 text-[13px] text-[var(--ink-soft)]">
                          {(() => {
                            const sourceText = `${SOURCE_TYPE_LABEL[req.sourceType]}: ${req.sourceTarget}`;
                            return (
                              <span className={getRequirementTableTextClass('source')} title={sourceText}>
                                {sourceText}
                              </span>
                            );
                          })()}
                        </td>

                        {/* 所属项目 */}
                        <td className="px-4 py-3 text-[12px] text-[var(--ink-soft)]">
                          {(() => {
                            const projectName = allProjects.find((p) => p.id === req.projectId)?.name ?? '-';
                            return (
                              <span className={getRequirementTableTextClass('project')} title={projectName}>
                                {projectName}
                              </span>
                            );
                          })()}
                        </td>

                        {/* 需求类型 */}
                        <td className="px-4 py-3 text-[12px] text-[var(--ink-soft)]">
                          {(() => {
                            const typeName = types.find((t) => t.id === req.typeId)?.name ?? '-';
                            return (
                              <span className={getRequirementTableTextClass('type')} title={typeName}>
                                {typeName}
                              </span>
                            );
                          })()}
                        </td>

                        {/* 状态 */}
                        <td className={REQUIREMENT_TABLE_NOWRAP_CELL_CLASS}>
                          <span className={`${REQUIREMENT_TABLE_BADGE_CLASS} ${REQ_STATUS_COLOR[req.status]}`}>
                            {REQ_STATUS_LABEL[req.status]}
                          </span>
                        </td>

                        {/* 优先级 */}
                        <td className={REQUIREMENT_TABLE_NOWRAP_CELL_CLASS}>
                          <span className={`${REQUIREMENT_TABLE_SMALL_BADGE_CLASS} ${PRIORITY_COLORS[req.priority] ?? 'bg-zinc-100 text-zinc-500'}`}>
                            {req.priority}
                          </span>
                        </td>

                        {/* 所属版本 */}
                        <td className="px-4 py-3 text-[12px] text-[var(--ink-soft)]">
                          {(() => {
                            const versionName = resolveVersionName(req.versionId);
                            return (
                              <span className={getRequirementTableTextClass('version')} title={versionName}>
                                {versionName}
                              </span>
                            );
                          })()}
                        </td>

                        {/* 开发状态 */}
                        <td className={REQUIREMENT_TABLE_NOWRAP_CELL_CLASS}>
                          {(() => {
                            const devStatus = requirementDevStatusMap.get(req.id) ?? 'unscheduled';
                            return (
                              <span className={`${REQUIREMENT_TABLE_SMALL_BADGE_CLASS} ${REQ_DEV_STATUS_COLOR[devStatus]}`}>
                                {REQ_DEV_STATUS_LABEL[devStatus]}
                              </span>
                            );
                          })()}
                        </td>

                        {/* 录入人员 */}
                        <td className="px-4 py-3 text-[12px] text-[var(--ink-soft)]">
                          <span className={getRequirementTableTextClass('creator')} title={req.creator}>
                            {req.creator}
                          </span>
                        </td>

                        {/* 录入日期 */}
                        <td className="px-4 py-3 text-[var(--ink-muted)] tabular-nums whitespace-nowrap">
                          {new Date(req.createdAt).toISOString().slice(0, 10)}
                        </td>

                        {/* 操作 */}
                        <td className="px-3 py-3 text-right" onClick={(e) => e.stopPropagation()}>
                          <div className="flex items-center justify-end gap-0.5 whitespace-nowrap">
                            {/* 编辑：待评审/已采纳/已规划，且开发中不可编辑 */}
                            {canMutateRequirement(req) && (['pending_review', 'adopted', 'planned'] as const).includes(req.status as any) && canEditRequirement(req.id, devTasksByRequirement.get(req.id) ?? []) && (
                              <button
                                onClick={() => handleEdit(req)}
                                className="h-6 rounded px-1.5 text-[11px] font-medium text-[var(--ink-soft)] transition-colors hover:bg-[var(--bg-subtle)]"
                              >
                                编辑
                              </button>
                            )}
                            {/* 待评审：采纳/拒绝 */}
                            {canMutateRequirement(req) && req.status === 'pending_review' && (
                              <>
                                <button
                                  onClick={() => updateRequirement(req.id, { status: 'adopted' })}
                                  className="h-6 rounded px-1.5 text-[11px] font-medium text-emerald-600 transition-colors hover:bg-emerald-50"
                                >
                                  采纳
                                </button>
                                <button
                                  onClick={() => { setRejectingReq(req); setRejectReason(''); }}
                                  className="h-6 rounded px-1.5 text-[11px] font-medium text-red-600 transition-colors hover:bg-red-50"
                                >
                                  拒绝
                                </button>
                              </>
                            )}
                            {/* 已采纳/已规划：关闭 */}
                            {canMutateRequirement(req) && (req.status === 'adopted' || req.status === 'planned') && canCloseRequirement(req.id, devTasksByRequirement.get(req.id) ?? []) && (
                              <button
                                onClick={() => updateRequirement(req.id, { status: 'closed' })}
                                className="h-6 rounded px-1.5 text-[11px] font-medium text-orange-600 transition-colors hover:bg-orange-50"
                              >
                                关闭
                              </button>
                            )}
                            {/* 删除：待评审/已拒绝/已关闭（已采纳后不能直接删，需走拒绝） */}
                            {canMutateRequirement(req) && (['pending_review', 'rejected', 'closed'] as const).includes(req.status as any) && (
                              <button
                                onClick={() => deleteRequirement(req.id)}
                                className="h-6 rounded px-1.5 text-[11px] font-medium text-red-500 transition-colors hover:bg-red-50"
                              >
                                删除
                              </button>
                            )}
                          </div>
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
              <Pagination total={total} page={displayPage} pageSize={pageSize} onChange={handlePageChange} onPageSizeChange={setPageSize} />
            </>
          )}
        </div>
      </div>
      </main>

      {/* Detail drawer */}
      {viewingReq && (
        <RequirementDetail
          requirement={viewingReq}
          projects={allProjects.map((p) => ({ id: p.id, name: p.name }))}
          types={types}
          platforms={platforms}
          sourceTargets={sourceTargets}
          requirements={requirements}
          resolveVersionName={resolveVersionName}
          onClose={() => setViewingReq(null)}
          onEdit={canMutateRequirement(viewingReq) && canEditRequirement(viewingReq.id, devTasksByRequirement.get(viewingReq.id) ?? []) ? () => handleEdit(viewingReq) : undefined}
          onAdopt={canMutateRequirement(viewingReq) ? () => { updateRequirement(viewingReq.id, { status: 'adopted' }); setViewingReq(null); } : undefined}
          onReject={canMutateRequirement(viewingReq) ? () => { setRejectingReq(viewingReq); setRejectReason(''); setViewingReq(null); } : undefined}
          onCloseReq={canMutateRequirement(viewingReq) && canCloseRequirement(viewingReq.id, devTasksByRequirement.get(viewingReq.id) ?? []) ? () => { updateRequirement(viewingReq.id, { status: 'closed' }); setViewingReq(null); } : undefined}
          onDelete={canMutateRequirement(viewingReq) ? () => { deleteRequirement(viewingReq.id); setViewingReq(null); } : undefined}
        />
      )}

      {/* Modal */}
      {showModal && (
        <RequirementModal
          open={true}
          initial={editingReq}
          products={overview.map((p) => ({ id: p.id, name: p.name }))}
          projects={allProjects.map((p) => ({ id: p.id, name: p.name, productId: p.productId }))}
          versions={allVersions.map((v) => ({ id: v.id, name: v.name, projectId: v.projectId }))}
          sourceTargets={sourceTargets}
          types={types}
          platforms={platforms}
          requirements={requirements}
          currentUserName={currentUserName}
          onClose={() => { setShowModal(false); setEditingReq(null); }}
          onSubmit={(data) => {
            if (editingReq) {
              const versionPatch = getRequirementVersionSelectionPatch(
                editingReq,
                data.versionId,
                data.versionId !== editingReq.versionId ? currentUserName : editingReq.addedToVersionBy,
              );
              updateRequirement(editingReq.id, { ...data, ...versionPatch });
            } else {
              createRequirement(data);
            }
            setShowModal(false);
            setEditingReq(null);
          }}
          onOpenDrawer={(type) => setDrawerType(type)}
        />
      )}

      {/* Drawer */}
      {drawerType === 'source' && (
        <SourceDrawer
          open={true}
          items={sourceTargets}
          onClose={() => setDrawerType(null)}
          onAdd={addSourceTarget}
          onUpdate={updateSourceTarget}
          onDelete={deleteSourceTarget}
        />
      )}
      {drawerType === 'type' && (
        <DictDrawer
          open={true}
          title="需求类型管理"
          items={types}
          onClose={() => setDrawerType(null)}
          onAdd={addType}
          onUpdate={updateType}
          onDelete={deleteType}
        />
      )}
      {drawerType === 'platform' && (
        <DictDrawer
          open={true}
          title="支持端管理"
          items={platforms}
          onClose={() => setDrawerType(null)}
          onAdd={addPlatform}
          onUpdate={updatePlatform}
          onDelete={deletePlatform}
        />
      )}

      {/* 拒绝原因弹窗 */}
      {rejectingReq && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40" onClick={() => setRejectingReq(null)}>
          <div className="w-full max-w-sm rounded-xl bg-[var(--bg-card)] border border-[var(--line)] p-5 shadow-[var(--shadow-md)]" onClick={(e) => e.stopPropagation()}>
            <h3 className="text-[13px] font-semibold text-[var(--ink)] mb-3">拒绝需求</h3>
            <p className="text-[12px] text-[var(--ink-muted)] mb-2">需求：{rejectingReq.title}</p>
            <textarea
              value={rejectReason}
              onChange={(e) => setRejectReason(e.target.value)}
              placeholder="请填写拒绝原因..."
              rows={3}
              className="w-full rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 py-2 text-[13px] text-[var(--ink)] placeholder:text-[var(--ink-muted)] focus:border-[var(--accent)] focus:outline-none resize-none"
            />
            <div className="flex justify-end gap-2 mt-3">
              <button onClick={() => setRejectingReq(null)} className="h-8 px-3 rounded-lg text-[12px] font-medium border border-[var(--line)] text-[var(--ink-soft)] hover:bg-[var(--bg-subtle)]">
                取消
              </button>
              <button
                onClick={() => {
                  if (!rejectReason.trim()) return;
                  updateRequirement(rejectingReq.id, { status: 'rejected', description: rejectingReq.description + `\n\n【拒绝原因】${rejectReason.trim()}` });
                  setRejectingReq(null);
                }}
                disabled={!rejectReason.trim()}
                className="h-8 px-3 rounded-lg text-[12px] font-medium bg-red-500 text-white hover:bg-red-600 disabled:opacity-50 disabled:cursor-not-allowed"
              >
                确认拒绝
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
