'use client';

import { useEffect, useMemo, useState } from 'react';
import { Plus, Pencil, Trash2, X, Check, ExternalLink, FileUp, Link2, Play, ArrowRightLeft } from 'lucide-react';
import type { ProductPlanKind, ProductPlanReviewFailureType, ProductPlanReviewResult, VersionPlan, PlanTask } from '@/lib/version-plan';
import {
  calcPlanDuration,
  formatDuration,
  calcTotalDuration,
  calcPlanProgress,
  sortPlansNewestFirst,
  getPlanLogsForPlans,
  getResearchDirectionPresetOptions,
  getResearchDirectionProgressSummary,
  getRequirementCoverageSummary,
  PRODUCT_PLAN_KIND_LABEL,
  PRODUCT_PLAN_REVIEW_FAILURE_OPTIONS,
  PRODUCT_PLAN_REVIEW_RESULT_LABEL,
} from '@/lib/version-plan';
import { formatDateTime } from '@/lib/format';
import { FieldError } from '@/components/FieldError';
import { FilterSelect } from '@/components/FilterSelect';
import { WorkDateTimePicker } from '@/components/WorkDateTimePicker';
import { AiDecomposeButton } from './AiDecomposeButton';
import { PlanLinkedRequirementReferenceList, PlanLogTimeline, PlanRequirementCoveragePanel, PlanResearchDirectionPanel } from './PlanRequirementCoveragePanel';
import type { VersionWithContext } from '@/lib/derive';
import type { Requirement } from '@/lib/requirement';
import { mergeSelectedRequirementOptions } from '@/lib/requirement-selector';
import { canEditPlanRequirementCoverage, canTogglePlanChecklist, getPlanCompletionState } from '@/lib/version-plan-workflow';
import type { PlanResultPayload } from '@/lib/version-plan-workflow';

interface Props {
  plans: VersionPlan[];
  versionId: string;
  version?: VersionWithContext;
  versionDeadline?: string;
  currentUserName: string;
  planType: 'research' | 'product' | 'ui';
  versionMembers: { role: string; name: string }[];
  linkedRequirements?: Requirement[];
  allRequirements?: Requirement[];
  onCreate: (data: Omit<VersionPlan, 'id' | 'createdAt'>) => void;
  onUpdate: (id: string, data: Partial<VersionPlan>) => void;
  onComplete: (id: string, result: PlanResultPayload) => { ok: boolean; message?: string } | void;
  onDelete: (id: string) => void;
  readOnly?: boolean;
}

const TYPE_LABEL = { research: '调研', product: '产品方案', ui: 'UI设计' };
const STATUS_STYLE = {
  pending: 'bg-zinc-100 text-zinc-600',
  in_progress: 'bg-blue-50 text-blue-600 border-blue-200',
  completed: 'bg-green-50 text-green-700 border-green-200',
};
const STATUS_LABEL = { pending: '未开始', in_progress: '进行中', completed: '已完成' };

function getProductPlanKind(plan: VersionPlan): ProductPlanKind {
  return plan.productPlanKind ?? 'design';
}

function getSubmitActionLabel(plan: VersionPlan): string {
  if (plan.type === 'product') {
    return getProductPlanKind(plan) === 'review' ? '提交评审结论' : '提交原型地址';
  }
  return '提交成果';
}

function getFailureLabels(types?: ProductPlanReviewFailureType[]): string[] {
  if (!types?.length) return [];
  return types
    .map((type) => PRODUCT_PLAN_REVIEW_FAILURE_OPTIONS.find((option) => option.value === type)?.label)
    .filter(Boolean) as string[];
}

export function PlanTab({ plans, versionId, version, versionDeadline, currentUserName, planType, versionMembers, linkedRequirements, allRequirements, onCreate, onUpdate, onComplete, onDelete, readOnly = false }: Props) {
  const [showCreateModal, setShowCreateModal] = useState(false);
  const [editingPlan, setEditingPlan] = useState<VersionPlan | null>(null);
  const [completingPlan, setCompletingPlan] = useState<VersionPlan | null>(null);
  const [transferPlanId, setTransferPlanId] = useState<string | null>(null);
  const [transferTo, setTransferTo] = useState('');

  const typePlans = sortPlansNewestFirst(plans.filter((p) => p.versionId === versionId && p.type === planType));
  const totalDuration = calcTotalDuration(typePlans);

  return (
    <div className="-m-5 h-[calc(100vh-98px)] min-h-[520px]">
      {false && planType === 'research' && (
        <div className="flex items-center justify-between">
          <div className="flex items-center gap-3">
            <span className="text-[12px] text-[var(--ink-muted)]">{typePlans.length} 个{TYPE_LABEL[planType]}计划</span>
            <span className="text-[12px] text-[var(--ink-soft)]">已耗时：<span className="font-medium text-[var(--ink)]">{totalDuration}</span></span>
            {versionDeadline && <span className="text-[12px] text-[var(--ink-muted)]">版本截止：<span className="font-medium text-red-500">{versionDeadline}</span></span>}
          </div>
          <button onClick={() => setShowCreateModal(true)} 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>
      )}

      {false && typePlans.length === 0 && planType === 'research' ? (
        <div className="rounded-xl border border-[var(--line)] bg-[var(--bg-card)] p-12 text-center text-[13px] text-[var(--ink-muted)]">
          暂无{TYPE_LABEL[planType]}计划
        </div>
      ) : false && planType === 'research' ? (
        <div className="space-y-3">
          {typePlans.map((plan) => {
            const now = new Date().toISOString();
            // 自动开始：如果到了计划开始日期且状态还是 pending，视为已开始
            const autoStarted = plan.status === 'pending' && plan.startTime && new Date(plan.startTime) <= new Date();
            const effectiveStatus = autoStarted ? 'in_progress' : plan.status;
            const effectiveStartAt = plan.actualStartAt || (autoStarted ? plan.startTime : null);
            const completionState = getPlanCompletionState(plan);
            const canToggle = canTogglePlanChecklist(plan);
            const canEditCoverage = canEditPlanRequirementCoverage(plan);
            const requirementOptions = mergeSelectedRequirementOptions(linkedRequirements ?? [], allRequirements ?? [], plan.linkedRequirementIds ?? []);
            // 耗时用实际时间戳计算
            const dur = plan.status === 'completed' && plan.completedAt && plan.actualStartAt
              ? calcPlanDuration(plan.actualStartAt, plan.completedAt)
              : effectiveStatus === 'in_progress' && effectiveStartAt
                ? calcPlanDuration(effectiveStartAt, now)
                : { days: 0, hours: 0 };
            const durText = dur.days > 0 || dur.hours > 0 ? formatDuration(dur.days, dur.hours) : '-';
            // 如果自动开始了，触发 store 更新（副作用）
            if (autoStarted && !plan.actualStartAt) {
              onUpdate(plan.id, { status: 'in_progress' });
            }
            return (
              <div key={plan.id} className="rounded-xl border border-[var(--line)] bg-[var(--bg-card)] p-4 shadow-[var(--shadow-sm)]">
                <div className={plan.type === 'research' ? '' : 'grid gap-4 xl:grid-cols-[minmax(0,1fr)_320px]'}>
                  <div className="min-w-0">
                <div className="flex items-start justify-between gap-4">
                  <div className="min-w-0 flex-1">
                    <div className="flex flex-wrap items-center gap-2">
                      <span className="min-w-0 truncate text-[14px] font-semibold text-[var(--ink)]" title={plan.title}>{plan.title}</span>
                      <span className={`inline-flex shrink-0 items-center rounded-md px-2 py-0.5 text-[10px] font-medium border ${STATUS_STYLE[effectiveStatus]}`}>
                        {STATUS_LABEL[effectiveStatus]}
                      </span>
                      {plan.type === 'product' && (
                        <span className="inline-flex shrink-0 items-center rounded-md border border-[var(--line)] bg-[var(--bg-subtle)] px-2 py-0.5 text-[10px] font-medium text-[var(--ink-muted)]">
                          {PRODUCT_PLAN_KIND_LABEL[getProductPlanKind(plan)]}
                        </span>
                      )}
                      {plan.type === 'product' && plan.reviewResult && (
                        <span className={`inline-flex shrink-0 items-center rounded-md px-2 py-0.5 text-[10px] font-medium ${plan.reviewResult === 'passed' ? 'bg-emerald-50 text-emerald-700' : 'bg-red-50 text-red-700'}`}>
                          {PRODUCT_PLAN_REVIEW_RESULT_LABEL[plan.reviewResult]}
                        </span>
                      )}
                    </div>
                    <dl className="mt-3 grid grid-cols-1 gap-x-5 gap-y-2 border-y border-[var(--line)] py-3 text-[12px] sm:grid-cols-2 lg:grid-cols-4">
                      <div>
                        <dt className="text-[11px] text-[var(--ink-muted)]">负责人</dt>
                        <dd className="mt-0.5 font-medium text-[var(--ink)]">{plan.owner}</dd>
                      </div>
                      <div className="sm:col-span-2">
                        <dt className="text-[11px] text-[var(--ink-muted)]">计划时间</dt>
                        <dd className="mt-0.5 font-medium text-[var(--ink)]">{formatDateTime(plan.startTime)} → {formatDateTime(plan.endTime)}</dd>
                      </div>
                      <div>
                        <dt className="text-[11px] text-[var(--ink-muted)]">已耗时</dt>
                        <dd className="mt-0.5 font-semibold text-[var(--ink)]">{durText}</dd>
                      </div>
                      {plan.actualStartAt && (
                        <div>
                          <dt className="text-[11px] text-[var(--ink-muted)]">实际开始</dt>
                          <dd className="mt-0.5 font-medium text-blue-600">{formatDateTime(plan.actualStartAt)}</dd>
                        </div>
                      )}
                      {plan.completedAt && (
                        <div>
                          <dt className="text-[11px] text-[var(--ink-muted)]">完成时间</dt>
                          <dd className="mt-0.5 font-medium text-green-600">{formatDateTime(plan.completedAt)}</dd>
                        </div>
                      )}
                    </dl>
                    {plan.overdueReason && (
                      <div className="mt-3 rounded-lg border border-red-100 bg-red-50 px-3 py-2 text-[11px] leading-5 text-red-700">超期原因：{plan.overdueReason}</div>
                    )}
                    {plan.remark && (
                      <div className="mt-3 border-l-2 border-[var(--accent)] pl-3">
                        <div className="text-[11px] font-medium text-[var(--ink-muted)]">备注</div>
                        <div className="mt-1 max-h-20 overflow-y-auto whitespace-pre-wrap pr-1 text-[12px] leading-5 text-[var(--ink-soft)]">{plan.remark}</div>
                      </div>
                    )}
                    {plan.status === 'completed' && plan.resultUrl && (
                      <div className="flex items-center gap-1.5 mt-2">
                        {plan.resultType === 'link' ? <Link2 className="h-3 w-3 text-[var(--accent)]" /> : <FileUp className="h-3 w-3 text-[var(--accent)]" />}
                        <a href={plan.resultUrl} target="_blank" rel="noopener noreferrer" className="text-[12px] text-[var(--accent)] hover:underline flex items-center gap-1">
                          {plan.resultTitle || plan.resultFileName || '查看成果'}<ExternalLink className="h-3 w-3" />
                        </a>
                      </div>
                    )}
                    {plan.status === 'completed' && plan.type === 'product' && getProductPlanKind(plan) === 'review' && plan.reviewResult && (
                      <div className={`mt-2 rounded-lg border px-3 py-2 ${plan.reviewResult === 'passed' ? 'border-emerald-200 bg-emerald-50' : 'border-red-200 bg-red-50'}`}>
                        <div className={`text-[12px] font-medium ${plan.reviewResult === 'passed' ? 'text-emerald-700' : 'text-red-700'}`}>
                          {PRODUCT_PLAN_REVIEW_RESULT_LABEL[plan.reviewResult]}
                        </div>
                        {plan.reviewResult === 'failed' && (
                          <div className="mt-1 space-y-1 text-[11px] text-red-700">
                            {getFailureLabels(plan.reviewFailureTypes).length > 0 && <div>类型：{getFailureLabels(plan.reviewFailureTypes).join('、')}</div>}
                            {plan.reviewFailureReason && <div>原因：{plan.reviewFailureReason}</div>}
                          </div>
                        )}
                      </div>
                    )}
                    {/* 子任务 */}
                    {plan.type === 'research' && plan.tasks && plan.tasks.length > 0 && (
                      <div className="mt-3 space-y-2">
                        <div className="flex items-center gap-2">
                          <div className="flex-1 h-1.5 rounded-full bg-[var(--bg-subtle)] overflow-hidden">
                            <div className="h-full rounded-full bg-[var(--accent)] transition-all" style={{ width: `${calcPlanProgress(plan.tasks)}%` }} />
                          </div>
                          <span className="text-[11px] font-medium tabular-nums text-[var(--ink-soft)]">{calcPlanProgress(plan.tasks)}%</span>
                        </div>
                        <div className="space-y-1">
                          {plan.tasks.map((task) => (
                            <div key={task.id} className="flex items-center gap-2">
                              <button
                                disabled={!canToggle}
                                onClick={() => {
                                  if (!canToggle) return;
                                  const nextStatus = task.status === 'completed' ? 'pending' : 'completed';
                                  const updatedTasks = plan.tasks!.map((t) => t.id === task.id ? { ...t, status: nextStatus as PlanTask['status'] } : t);
                                  onUpdate(plan.id, { tasks: updatedTasks });
                                }}
                                className={`h-4 w-4 rounded border flex items-center justify-center shrink-0 transition-colors ${!canToggle ? 'opacity-40 cursor-not-allowed' : ''} ${task.status === 'completed' ? 'bg-[var(--accent)] border-[var(--accent)]' : 'border-[var(--line)]'}`}
                              >
                                {task.status === 'completed' && <Check className="h-2.5 w-2.5 text-white" strokeWidth={3} />}
                              </button>
                              <span className={`text-[12px] ${task.status === 'completed' ? 'line-through text-[var(--ink-muted)]' : 'text-[var(--ink)]'}`}>{task.title}</span>
                              <span className={`text-[10px] ${task.status === 'completed' ? 'text-green-600' : 'text-[var(--ink-muted)]'}`}>
                                {task.status === 'completed' ? '已完成' : '未完成'}
                              </span>
                            </div>
                          ))}
                        </div>
                      </div>
                    )}
                    {plan.linkedRequirementIds && plan.linkedRequirementIds.length > 0 && requirementOptions.length > 0 && (
                      <PlanRequirementCoveragePanel
                        plan={plan}
                        requirements={plan.linkedRequirementIds.map((rid) => requirementOptions.find((r) => r.id === rid)).filter(Boolean) as Requirement[]}
                        canEdit={canEditCoverage}
                        currentUserName={currentUserName}
                        onUpdate={onUpdate}
                      />
                    )}
                    {plan.status === 'in_progress' && !completionState.canSubmitResult && (
                      <p className="mt-2 text-[11px] text-[var(--ink-muted)]">还不能提交成果：{completionState.missingReasons.join('、')}</p>
                    )}
                  </div>
                  <div className="flex items-center gap-1 ml-3">
                    {plan.status === 'pending' && !autoStarted && (
                      <button onClick={() => onUpdate(plan.id, { status: 'in_progress' })} className="h-7 px-2 flex items-center gap-1 rounded-md text-[11px] font-medium text-blue-600 hover:bg-blue-50 border border-blue-200" title="提前开始">
                        <Play className="h-3 w-3" />开始
                      </button>
                    )}
                    {plan.status !== 'completed' && (
                      <>
                        <button onClick={() => setTransferPlanId(plan.id)} className="h-7 w-7 flex items-center justify-center rounded-md text-blue-500 hover:bg-blue-50" title="转交">
                          <ArrowRightLeft className="h-3.5 w-3.5" />
                        </button>
                        <button onClick={() => setEditingPlan(plan)} className="h-7 w-7 flex items-center justify-center rounded-md text-[var(--ink-muted)] hover:bg-[var(--bg-subtle)]" title="编辑">
                          <Pencil className="h-3.5 w-3.5" />
                        </button>
                        <button onClick={() => onDelete(plan.id)} className="h-7 w-7 flex items-center justify-center rounded-md text-red-500 hover:bg-red-50" title="删除">
                          <Trash2 className="h-3.5 w-3.5" />
                        </button>
                      </>
                    )}
                  </div>
                </div>
                {transferPlanId === plan.id && (
                  <div className="mt-3 pt-3 border-t border-[var(--line)] flex items-center gap-2">
                    <span className="text-[11px] text-[var(--ink-muted)]">转交给：</span>
                    <FilterSelect
                      value={transferTo || 'all'}
                      onChange={(value) => setTransferTo(value === 'all' ? '' : value)}
                      options={versionMembers.filter((m) => m.name !== plan.owner).map((m) => ({ value: m.name, label: m.name }))}
                      allLabel="选择参与人员"
                      className="flex-1"
                    />
                    <button onClick={() => { if (transferTo) { onUpdate(plan.id, { owner: transferTo }); setTransferPlanId(null); setTransferTo(''); } }} disabled={!transferTo} className="h-7 px-2.5 rounded-lg text-[11px] font-medium bg-blue-500 text-white disabled:opacity-50">确认</button>
                    <button onClick={() => { setTransferPlanId(null); setTransferTo(''); }} className="h-7 px-2 text-[11px] text-[var(--ink-muted)]">取消</button>
                  </div>
                )}
                {plan.status !== 'completed' && completionState.canSubmitResult && (
                  <div className="mt-3 rounded-lg bg-green-50 border border-green-200 px-3 py-2 flex items-center justify-between">
                    <span className="text-[12px] text-green-700">已满足{getSubmitActionLabel(plan)}条件</span>
                    <button onClick={() => setCompletingPlan(plan)} className="text-[11px] font-medium text-green-700 hover:text-green-900 underline">{getSubmitActionLabel(plan)}</button>
                  </div>
                )}
                  </div>
                  {plan.type !== 'research' && (
                    <PlanLogTimeline
                      logs={plan.logs}
                      className="border-t border-[var(--line)] pt-4 xl:border-l xl:border-t-0 xl:pt-0 xl:pl-4"
                    />
                  )}
              </div>
              </div>
            );
          })}
        </div>
      ) : (
        <ProductUiPlanWorkspace
          typePlans={typePlans}
          planType={planType}
          totalDuration={totalDuration}
          versionDeadline={versionDeadline}
          version={version}
          currentUserName={currentUserName}
          versionMembers={versionMembers}
          linkedRequirements={linkedRequirements}
          allRequirements={allRequirements}
          transferPlanId={transferPlanId}
          transferTo={transferTo}
          onSetTransferPlanId={setTransferPlanId}
          onTransferToChange={setTransferTo}
          onUpdate={onUpdate}
          onDelete={onDelete}
          onEditPlan={setEditingPlan}
          onOpenComplete={setCompletingPlan}
          onCreatePlan={() => setShowCreateModal(true)}
          readOnly={readOnly}
        />
      )}

      {(showCreateModal || editingPlan) && !readOnly && (
        <PlanFormModal
          initial={editingPlan}
          planType={planType}
          versionId={versionId}
          versionDeadline={versionDeadline}
          currentUserName={currentUserName}
          linkedRequirements={linkedRequirements}
          allRequirements={allRequirements}
          onClose={() => { setShowCreateModal(false); setEditingPlan(null); }}
          onSubmit={(data) => {
            if (editingPlan) onUpdate(editingPlan.id, data);
            else onCreate(data as any);
            setShowCreateModal(false);
            setEditingPlan(null);
          }}
        />
      )}

      {completingPlan && !readOnly && (
        <CompleteModal
          plan={completingPlan}
          onClose={() => setCompletingPlan(null)}
          onSubmit={(result) => {
            const response = onComplete(completingPlan.id, result);
            if (response && typeof response === 'object' && 'ok' in response && !response.ok) {
              alert(response.message || '计划未满足完成条件');
              return;
            }
            setCompletingPlan(null);
          }}
        />
      )}
    </div>
  );
}

function getPlanRuntime(plan: VersionPlan): {
  autoStarted: boolean;
  effectiveStatus: VersionPlan['status'];
  effectiveStartAt: string | null;
} {
  const autoStarted = plan.status === 'pending' && Boolean(plan.startTime) && new Date(plan.startTime) <= new Date();
  return {
    autoStarted,
    effectiveStatus: autoStarted ? 'in_progress' : plan.status,
    effectiveStartAt: plan.actualStartAt || (autoStarted ? plan.startTime : null),
  };
}

function getPlanDurationText(plan: VersionPlan, effectiveStatus: VersionPlan['status'], effectiveStartAt: string | null, now: string): string {
  const dur = plan.status === 'completed' && plan.completedAt && plan.actualStartAt
    ? calcPlanDuration(plan.actualStartAt, plan.completedAt)
    : effectiveStatus === 'in_progress' && effectiveStartAt
      ? calcPlanDuration(effectiveStartAt, now)
      : { days: 0, hours: 0 };
  return dur.days > 0 || dur.hours > 0 ? formatDuration(dur.days, dur.hours) : '-';
}

function ProductUiPlanWorkspace({
  typePlans,
  planType,
  totalDuration,
  versionDeadline,
  version,
  currentUserName,
  versionMembers,
  linkedRequirements,
  allRequirements,
  transferPlanId,
  transferTo,
  onSetTransferPlanId,
  onTransferToChange,
  onUpdate,
  onDelete,
  onEditPlan,
  onOpenComplete,
  onCreatePlan,
  readOnly,
}: {
  typePlans: VersionPlan[];
  planType: VersionPlan['type'];
  totalDuration: string;
  versionDeadline?: string;
  version?: VersionWithContext;
  currentUserName: string;
  versionMembers: { role: string; name: string }[];
  linkedRequirements?: Requirement[];
  allRequirements?: Requirement[];
  transferPlanId: string | null;
  transferTo: string;
  onSetTransferPlanId: (id: string | null) => void;
  onTransferToChange: (name: string) => void;
  onUpdate: (id: string, data: Partial<VersionPlan>) => void;
  onDelete: (id: string) => void;
  onEditPlan: (plan: VersionPlan) => void;
  onOpenComplete: (plan: VersionPlan) => void;
  onCreatePlan: () => void;
  readOnly: boolean;
}) {
  const [selectedPlanId, setSelectedPlanId] = useState<string | null>(typePlans[0]?.id ?? null);
  const selectedPlan = typePlans.find((plan) => plan.id === selectedPlanId) ?? typePlans[0];
  const selectedPlanIdOrFirst = selectedPlan?.id;
  const allLogs = useMemo(() => getPlanLogsForPlans(typePlans), [typePlans]);

  useEffect(() => {
    if (readOnly) return;
    typePlans.forEach((plan) => {
      const { autoStarted } = getPlanRuntime(plan);
      if (autoStarted && !plan.actualStartAt) {
        onUpdate(plan.id, { status: 'in_progress' });
      }
    });
  }, [typePlans, onUpdate, readOnly]);

  return (
    <div className="flex h-full min-h-0">
      <aside className="flex h-full 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 gap-2 border-b border-[var(--line)] px-4">
          <div className="text-[14px] font-semibold text-[var(--ink)]">任务计划</div>
          {!readOnly && (
            <button onClick={onCreatePlan} className="flex h-7 items-center gap-1.5 rounded-md bg-[var(--accent)] px-2.5 text-[11px] 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>
        <div className="shrink-0 space-y-2 border-b border-[var(--line)] p-3">
          <div className={`grid gap-2 ${versionDeadline ? 'grid-cols-2' : 'grid-cols-1'}`}>
            <div className="rounded-lg bg-[var(--bg-subtle)] px-3 py-2">
              <div className="text-[10px] text-[var(--ink-muted)]">已耗时</div>
              <div className="mt-0.5 truncate text-[13px] font-semibold text-[var(--ink)]">{totalDuration}</div>
            </div>
            {versionDeadline && (
              <div className="rounded-lg bg-red-50 px-3 py-2">
                <div className="text-[10px] text-red-500">版本截止</div>
                <div className="mt-0.5 truncate text-[13px] font-semibold text-red-600">{versionDeadline}</div>
              </div>
            )}
          </div>
        </div>
        <div className="min-h-0 flex-1 space-y-1 overflow-y-auto p-2">
          {typePlans.map((plan) => {
            const { effectiveStatus } = getPlanRuntime(plan);
            const summary = plan.type === 'research'
              ? getResearchDirectionProgressSummary(plan)
              : getRequirementCoverageSummary(plan);
            const isSelected = plan.id === selectedPlanIdOrFirst;
            return (
              <button
                key={plan.id}
                type="button"
                onClick={() => setSelectedPlanId(plan.id)}
                className={`w-full rounded-lg px-3 py-2 text-left transition-colors ${isSelected ? 'bg-[var(--accent-soft)] text-[var(--accent)]' : 'text-[var(--ink-soft)] hover:bg-[var(--bg-subtle)]'}`}
              >
                <div className="flex min-w-0 items-start justify-between gap-2">
                  <span className="min-w-0 truncate text-[12px] font-semibold" title={plan.title}>{plan.title}</span>
                  <span className={`shrink-0 rounded-md border px-1.5 py-0.5 text-[10px] font-medium ${STATUS_STYLE[effectiveStatus]}`}>
                    {STATUS_LABEL[effectiveStatus]}
                  </span>
                </div>
                <div className="mt-2 flex items-center justify-between gap-2 text-[11px]">
                  <span className="truncate">{plan.owner}</span>
                  {plan.type === 'product' ? (
                    <span className="shrink-0">{PRODUCT_PLAN_KIND_LABEL[getProductPlanKind(plan)]}</span>
                  ) : (
                    <span className="shrink-0">{TYPE_LABEL[plan.type]}</span>
                  )}
                </div>
                {plan.type === 'product' && plan.reviewResult && (
                  <div className={`mt-2 inline-flex rounded-md px-1.5 py-0.5 text-[10px] font-medium ${plan.reviewResult === 'passed' ? 'bg-emerald-50 text-emerald-700' : 'bg-red-50 text-red-700'}`}>
                    {PRODUCT_PLAN_REVIEW_RESULT_LABEL[plan.reviewResult]}
                  </div>
                )}
                <div className="mt-2 flex items-center gap-2">
                  <div className="h-1.5 flex-1 overflow-hidden rounded-full bg-[var(--bg-subtle)]">
                    <div className="h-full rounded-full bg-[var(--accent)]" style={{ width: `${summary.percent}%` }} />
                  </div>
                  <span className="shrink-0 text-[10px] tabular-nums text-[var(--ink-muted)]">
                    {summary.total > 0 ? `${summary.completed}/${summary.total}` : '0/0'}
                  </span>
                </div>
              </button>
            );
          })}
          {typePlans.length === 0 && (
            <div className="rounded-lg border border-dashed border-[var(--line)] bg-[var(--bg-subtle)] px-3 py-8 text-center text-[12px] text-[var(--ink-muted)]">
              暂无{TYPE_LABEL[planType]}计划
            </div>
          )}
        </div>
      </aside>

      <section className="flex h-full min-w-0 flex-1 flex-col bg-[var(--bg)]">
        {selectedPlan ? (
          <ProductUiPlanDetail
            plan={selectedPlan}
            planType={planType}
            version={version}
            currentUserName={currentUserName}
            versionMembers={versionMembers}
            linkedRequirements={linkedRequirements}
            allRequirements={allRequirements}
            transferPlanId={transferPlanId}
            transferTo={transferTo}
            onSetTransferPlanId={onSetTransferPlanId}
            onTransferToChange={onTransferToChange}
            onUpdate={onUpdate}
            onDelete={onDelete}
            onEditPlan={onEditPlan}
            onOpenComplete={onOpenComplete}
            readOnly={readOnly}
          />
        ) : (
          <div className="flex h-full items-center justify-center text-[13px] text-[var(--ink-muted)]">
            暂无{TYPE_LABEL[planType]}计划
          </div>
        )}
      </section>

      <PlanLogTimeline
        logs={allLogs}
        fillHeight
        className="flex h-full w-80 shrink-0 flex-col border-l border-[var(--line)] bg-[var(--bg-card)] p-4"
      />
    </div>
  );
}

function ProductUiPlanDetail({
  plan,
  planType,
  version,
  currentUserName,
  versionMembers,
  linkedRequirements,
  allRequirements,
  transferPlanId,
  transferTo,
  onSetTransferPlanId,
  onTransferToChange,
  onUpdate,
  onDelete,
  onEditPlan,
  onOpenComplete,
  readOnly,
}: {
  plan: VersionPlan;
  planType: VersionPlan['type'];
  version?: VersionWithContext;
  currentUserName: string;
  versionMembers: { role: string; name: string }[];
  linkedRequirements?: Requirement[];
  allRequirements?: Requirement[];
  transferPlanId: string | null;
  transferTo: string;
  onSetTransferPlanId: (id: string | null) => void;
  onTransferToChange: (name: string) => void;
  onUpdate: (id: string, data: Partial<VersionPlan>) => void;
  onDelete: (id: string) => void;
  onEditPlan: (plan: VersionPlan) => void;
  onOpenComplete: (plan: VersionPlan) => void;
  readOnly: boolean;
}) {
  const now = new Date().toISOString();
  const { autoStarted, effectiveStatus, effectiveStartAt } = getPlanRuntime(plan);
  const durText = getPlanDurationText(plan, effectiveStatus, effectiveStartAt, now);
  const completionState = getPlanCompletionState(plan);
  const canEditCoverage = !readOnly && canEditPlanRequirementCoverage(plan);
  const requirementOptions = mergeSelectedRequirementOptions(linkedRequirements ?? [], allRequirements ?? [], plan.linkedRequirementIds ?? []);
  const selectedRequirements = (plan.linkedRequirementIds ?? [])
    .map((rid) => requirementOptions.find((requirement) => requirement.id === rid))
    .filter(Boolean) as Requirement[];

  return (
    <div className="h-full overflow-y-auto p-5">
      <div className="flex items-start justify-between gap-4 border-b border-[var(--line)] pb-3">
        <div className="min-w-0">
          <div className="flex flex-wrap items-center gap-2">
            <h3 className="min-w-0 truncate text-[15px] font-semibold text-[var(--ink)]" title={plan.title}>{plan.title}</h3>
            <span className={`inline-flex shrink-0 items-center rounded-md border px-2 py-0.5 text-[10px] font-medium ${STATUS_STYLE[effectiveStatus]}`}>
              {STATUS_LABEL[effectiveStatus]}
            </span>
            {plan.type === 'product' && (
              <span className="inline-flex shrink-0 items-center rounded-md border border-[var(--line)] bg-[var(--bg-subtle)] px-2 py-0.5 text-[10px] font-medium text-[var(--ink-muted)]">
                {PRODUCT_PLAN_KIND_LABEL[getProductPlanKind(plan)]}
              </span>
            )}
            {plan.type === 'product' && plan.reviewResult && (
              <span className={`inline-flex shrink-0 items-center rounded-md px-2 py-0.5 text-[10px] font-medium ${plan.reviewResult === 'passed' ? 'bg-emerald-50 text-emerald-700' : 'bg-red-50 text-red-700'}`}>
                {PRODUCT_PLAN_REVIEW_RESULT_LABEL[plan.reviewResult]}
              </span>
            )}
          </div>
          <div className="mt-1 text-[11px] text-[var(--ink-muted)]">{TYPE_LABEL[plan.type]}</div>
        </div>
        {!readOnly && (
          <div className="flex shrink-0 items-center gap-1">
            {plan.status === 'pending' && !autoStarted && (
              <button onClick={() => onUpdate(plan.id, { status: 'in_progress' })} className="flex h-7 items-center gap-1 rounded-md border border-blue-200 px-2 text-[11px] font-medium text-blue-600 hover:bg-blue-50" title="提前开始">
                <Play className="h-3 w-3" />开始
              </button>
            )}
            {plan.status !== 'completed' && (
              <>
                <button onClick={() => onSetTransferPlanId(plan.id)} className="flex h-7 w-7 items-center justify-center rounded-md text-blue-500 hover:bg-blue-50" title="转交">
                  <ArrowRightLeft className="h-3.5 w-3.5" />
                </button>
                <button onClick={() => onEditPlan(plan)} className="flex h-7 w-7 items-center justify-center rounded-md text-[var(--ink-muted)] hover:bg-[var(--bg-subtle)]" title="编辑">
                  <Pencil className="h-3.5 w-3.5" />
                </button>
                <button onClick={() => onDelete(plan.id)} className="flex h-7 w-7 items-center justify-center rounded-md text-red-500 hover:bg-red-50" title="删除">
                  <Trash2 className="h-3.5 w-3.5" />
                </button>
              </>
            )}
          </div>
        )}
      </div>

      <dl className="mt-4 grid grid-cols-1 gap-3 text-[12px] sm:grid-cols-2 xl:grid-cols-4">
        <div className="rounded-lg bg-[var(--bg-subtle)] px-3 py-2">
          <dt className="text-[11px] text-[var(--ink-muted)]">负责人</dt>
          <dd className="mt-0.5 font-medium text-[var(--ink)]">{plan.owner}</dd>
        </div>
        <div className="rounded-lg bg-[var(--bg-subtle)] px-3 py-2 sm:col-span-2">
          <dt className="text-[11px] text-[var(--ink-muted)]">计划时间</dt>
          <dd className="mt-0.5 font-medium text-[var(--ink)]">{formatDateTime(plan.startTime)} → {formatDateTime(plan.endTime)}</dd>
        </div>
        <div className="rounded-lg bg-[var(--bg-subtle)] px-3 py-2">
          <dt className="text-[11px] text-[var(--ink-muted)]">已耗时</dt>
          <dd className="mt-0.5 font-semibold text-[var(--ink)]">{durText}</dd>
        </div>
        {plan.actualStartAt && (
          <div className="rounded-lg bg-blue-50 px-3 py-2">
            <dt className="text-[11px] text-blue-500">实际开始</dt>
            <dd className="mt-0.5 font-medium text-blue-700">{formatDateTime(plan.actualStartAt)}</dd>
          </div>
        )}
        {plan.completedAt && (
          <div className="rounded-lg bg-green-50 px-3 py-2">
            <dt className="text-[11px] text-green-600">完成时间</dt>
            <dd className="mt-0.5 font-medium text-green-700">{formatDateTime(plan.completedAt)}</dd>
          </div>
        )}
      </dl>

      {plan.overdueReason && (
        <div className="mt-3 rounded-lg border border-red-100 bg-red-50 px-3 py-2 text-[11px] leading-5 text-red-700">超期原因：{plan.overdueReason}</div>
      )}
      {plan.remark && (
        <div className="mt-3 border-l-2 border-[var(--accent)] pl-3">
          <div className="text-[11px] font-medium text-[var(--ink-muted)]">备注</div>
          <div className="mt-1 max-h-24 overflow-y-auto whitespace-pre-wrap pr-1 text-[12px] leading-5 text-[var(--ink-soft)]">{plan.remark}</div>
        </div>
      )}
      {plan.status === 'completed' && plan.resultUrl && (
        <div className="mt-3 flex flex-wrap items-center gap-2 rounded-lg border border-[var(--line)] px-3 py-2">
          {plan.resultType === 'link' ? <Link2 className="h-3.5 w-3.5 text-[var(--accent)]" /> : <FileUp className="h-3.5 w-3.5 text-[var(--accent)]" />}
          <a href={plan.resultUrl} target="_blank" rel="noopener noreferrer" className="flex min-w-0 items-center gap-1 text-[12px] text-[var(--accent)] hover:underline">
            <span className="truncate">{plan.resultTitle || plan.resultFileName || '查看成果'}</span><ExternalLink className="h-3 w-3 shrink-0" />
          </a>
          {planType === 'product' && version && !readOnly && (
            <AiDecomposeButton plan={plan} version={version} />
          )}
        </div>
      )}
      {plan.status === 'completed' && plan.type === 'product' && getProductPlanKind(plan) === 'review' && plan.reviewResult && (
        <div className={`mt-3 rounded-lg border px-3 py-2 ${plan.reviewResult === 'passed' ? 'border-emerald-200 bg-emerald-50' : 'border-red-200 bg-red-50'}`}>
          <div className={`text-[12px] font-medium ${plan.reviewResult === 'passed' ? 'text-emerald-700' : 'text-red-700'}`}>
            {PRODUCT_PLAN_REVIEW_RESULT_LABEL[plan.reviewResult]}
          </div>
          {plan.reviewResult === 'failed' && (
            <div className="mt-1 space-y-1 text-[11px] text-red-700">
              {getFailureLabels(plan.reviewFailureTypes).length > 0 && <div>类型：{getFailureLabels(plan.reviewFailureTypes).join('、')}</div>}
              {plan.reviewFailureReason && <div>原因：{plan.reviewFailureReason}</div>}
            </div>
          )}
        </div>
      )}

      {plan.type === 'research' && (
        <PlanResearchDirectionPanel
          plan={plan}
          canEdit={canEditCoverage}
          currentUserName={currentUserName}
          onUpdate={onUpdate}
        />
      )}
      {selectedRequirements.length > 0 && (
        plan.type === 'research' ? (
          <PlanLinkedRequirementReferenceList requirements={selectedRequirements} />
        ) : (
          <PlanRequirementCoveragePanel
            plan={plan}
            requirements={selectedRequirements}
            canEdit={canEditCoverage}
            currentUserName={currentUserName}
            onUpdate={onUpdate}
          />
        )
      )}
      {plan.status === 'in_progress' && !completionState.canSubmitResult && (
        <p className="mt-3 text-[11px] text-[var(--ink-muted)]">还不能提交成果：{completionState.missingReasons.join('、')}</p>
      )}

      {transferPlanId === plan.id && !readOnly && (
        <div className="mt-3 flex items-center gap-2 border-t border-[var(--line)] pt-3">
          <span className="text-[11px] text-[var(--ink-muted)]">转交给：</span>
          <FilterSelect
            value={transferTo || 'all'}
            onChange={(value) => onTransferToChange(value === 'all' ? '' : value)}
            options={versionMembers.filter((member) => member.name !== plan.owner).map((member) => ({ value: member.name, label: member.name }))}
            allLabel="选择参与人员"
            className="flex-1"
          />
          <button onClick={() => { if (transferTo) { onUpdate(plan.id, { owner: transferTo }); onSetTransferPlanId(null); onTransferToChange(''); } }} disabled={!transferTo} className="h-7 rounded-lg bg-blue-500 px-2.5 text-[11px] font-medium text-white disabled:opacity-50">确认</button>
          <button onClick={() => { onSetTransferPlanId(null); onTransferToChange(''); }} className="h-7 px-2 text-[11px] text-[var(--ink-muted)]">取消</button>
        </div>
      )}

      {plan.status !== 'completed' && completionState.canSubmitResult && !readOnly && (
        <div className="mt-3 flex items-center justify-between rounded-lg border border-green-200 bg-green-50 px-3 py-2">
          <span className="text-[12px] text-green-700">已满足{getSubmitActionLabel(plan)}条件</span>
          <button onClick={() => onOpenComplete(plan)} className="text-[11px] font-medium text-green-700 underline hover:text-green-900">{getSubmitActionLabel(plan)}</button>
        </div>
      )}
    </div>
  );
}

function PlanFormModal({ initial, planType, versionId, versionDeadline, currentUserName, linkedRequirements, allRequirements, onClose, onSubmit }: {
  initial: VersionPlan | null;
  planType: 'research' | 'product' | 'ui';
  versionId: string;
  versionDeadline?: string;
  currentUserName: string;
  linkedRequirements?: Requirement[];
  allRequirements?: Requirement[];
  onClose: () => void;
  onSubmit: (data: any) => void;
}) {
  const now = new Date().toISOString().slice(0, 16);
  const [title, setTitle] = useState(initial?.title ?? '');
  const [owner] = useState(initial?.owner ?? currentUserName);
  const [startTime, setStartTime] = useState(initial?.startTime?.slice(0, 16) ?? now);
  const [endTime, setEndTime] = useState(initial?.endTime?.slice(0, 16) ?? '');
  const [remark, setRemark] = useState(initial?.remark ?? '');
  const [productPlanKind, setProductPlanKind] = useState<ProductPlanKind>(initial?.productPlanKind ?? 'design');
  const [tasks, setTasks] = useState<PlanTask[]>(initial?.tasks ?? []);
  const [newTaskTitle, setNewTaskTitle] = useState('');
  const [overdueReason, setOverdueReason] = useState(initial?.overdueReason ?? '');
  const [selectedReqs, setSelectedReqs] = useState<Set<string>>(new Set(initial?.linkedRequirementIds ?? []));
  const [endTimeError, setEndTimeError] = useState('');
  const requirementOptions = useMemo(
    () => mergeSelectedRequirementOptions(linkedRequirements ?? [], allRequirements ?? [], Array.from(selectedReqs)),
    [linkedRequirements, allRequirements, selectedReqs],
  );
  const researchDirectionPresetOptions = useMemo(() => getResearchDirectionPresetOptions(tasks), [tasks]);
  const isOverdue = !!(versionDeadline && endTime && new Date(endTime) > new Date(versionDeadline));

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (!title.trim() || !endTime) return;
    if (startTime && endTime && new Date(endTime).getTime() <= new Date(startTime).getTime()) {
      setEndTimeError('结束日期必须晚于开始日期');
      return;
    }
    setEndTimeError('');
    if (isOverdue && !overdueReason.trim()) return;
    if (planType === 'research' && tasks.length === 0) return;
    onSubmit({
      versionId,
      type: planType,
      title: title.trim(),
      owner: owner.trim() || currentUserName,
      startTime,
      endTime,
      status: initial?.status ?? 'pending',
      productPlanKind: planType === 'product' ? productPlanKind : undefined,
      linkedRequirementIds: requirementOptions.length > 0 ? Array.from(selectedReqs) : undefined,
      tasks: planType === 'research' && tasks.length > 0 ? tasks : undefined,
      remark: remark.trim() || undefined,
      overdueReason: isOverdue ? overdueReason.trim() : undefined,
      addedBy: currentUserName,
    });
  };

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40" onClick={onClose}>
      <div className="w-full max-w-md rounded-2xl bg-[var(--bg-card)] border border-[var(--line)] p-5 shadow-[var(--shadow-md)]" onClick={(e) => e.stopPropagation()}>
        <div className="flex items-center justify-between mb-4">
          <h3 className="text-[13px] font-semibold text-[var(--ink)]">{initial ? '编辑' : '新建'}{TYPE_LABEL[planType]}计划</h3>
          <button onClick={onClose} className="p-1 rounded hover:bg-[var(--bg-subtle)] text-[var(--ink-muted)]"><X className="h-4 w-4" /></button>
        </div>
        <form onSubmit={handleSubmit} className="space-y-3">
          <div>
            <label className="text-[12px] font-medium text-[var(--ink-soft)] mb-1 block">标题</label>
            <input value={title} onChange={(e) => setTitle(e.target.value)} required className="h-9 w-full rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 text-[13px] focus:border-[var(--accent)] focus:outline-none" />
          </div>
          <div>
            <label className="text-[12px] font-medium text-[var(--ink-soft)] mb-1 block">负责人</label>
            <input value={owner} readOnly className="h-9 w-full rounded-lg border border-[var(--line)] bg-[var(--bg-subtle)] px-3 text-[13px] text-[var(--ink-muted)] cursor-not-allowed" />
          </div>
          {planType === 'product' && (
            <div>
              <label className="text-[12px] font-medium text-[var(--ink-soft)] mb-1.5 block">方案类型</label>
              <div className="grid grid-cols-2 gap-2">
                {(['design', 'review'] as ProductPlanKind[]).map((kind) => (
                  <label
                    key={kind}
                    className={`flex min-h-16 cursor-pointer items-start gap-2 rounded-lg border px-3 py-2 transition-colors ${productPlanKind === kind ? 'border-[var(--accent)] bg-[var(--accent-soft)]' : 'border-[var(--line)] bg-[var(--bg-card)] hover:bg-[var(--bg-subtle)]'}`}
                  >
                    <input
                      type="radio"
                      name="productPlanKind"
                      value={kind}
                      checked={productPlanKind === kind}
                      onChange={() => setProductPlanKind(kind)}
                      className="mt-0.5 h-3.5 w-3.5"
                    />
                    <span className="min-w-0">
                      <span className="block text-[12px] font-medium text-[var(--ink)]">{PRODUCT_PLAN_KIND_LABEL[kind]}</span>
                      <span className="mt-0.5 block text-[11px] leading-4 text-[var(--ink-muted)]">
                        {kind === 'design' ? '提交最终原型链接，用于后续 AI 拆解。' : '记录方案是否通过评审，不通过时沉淀原因类型。'}
                      </span>
                    </span>
                  </label>
                ))}
              </div>
            </div>
          )}
          <div className="grid grid-cols-2 gap-3">
            <div>
              <label className="text-[12px] font-medium text-[var(--ink-soft)] mb-1 block">计划开始时间</label>
              <WorkDateTimePicker
                value={startTime}
                onChange={setStartTime}
                placeholder="选择计划开始时间"
                defaultHour={9}
              />
            </div>
            <div>
              <label className="text-[12px] font-medium text-[var(--ink-soft)] mb-1 block">计划截止时间</label>
              <WorkDateTimePicker
                value={endTime}
                onChange={(next) => { setEndTime(next); setEndTimeError(''); }}
                placeholder="选择计划截止时间"
                defaultHour={18}
                popoverAlign="right"
              />
              <FieldError message={endTimeError} />
            </div>
          </div>
          {versionDeadline && (
            <div className="text-[11px] text-[var(--ink-muted)] -mt-1">版本截止日期：<span className="text-red-500 font-medium">{versionDeadline}</span></div>
          )}
          {isOverdue && (
            <div className="rounded-lg bg-red-50 border border-red-200 p-3 space-y-2">
              <div className="text-[12px] text-red-700 font-medium">⚠ 结束日期超出版本截止日期，请说明原因</div>
              <textarea
                value={overdueReason}
                onChange={(e) => setOverdueReason(e.target.value)}
                rows={2}
                placeholder="例如：技术难点超预期、上游交付延误..."
                required
                className="w-full rounded-lg border border-red-200 bg-white px-3 py-2 text-[13px] focus:border-red-400 focus:outline-none resize-none"
              />
            </div>
          )}
          {requirementOptions.length > 0 && (
            <div>
              <label className="text-[12px] font-medium text-[var(--ink-soft)] mb-1.5 block">关联需求</label>
              <div className="mb-2 flex items-center justify-between">
                <span className="text-[11px] text-[var(--ink-muted)]">已选 {selectedReqs.size} / {requirementOptions.filter((req) => !req.isHistorical).length}</span>
                <div className="flex gap-2">
                  <button
                    type="button"
                    onClick={() => setSelectedReqs(new Set(requirementOptions.map((req) => req.id)))}
                    className="text-[11px] text-[var(--accent)] hover:underline"
                  >
                    全选
                  </button>
                  <button
                    type="button"
                    onClick={() => setSelectedReqs(new Set())}
                    className="text-[11px] text-[var(--ink-muted)] hover:underline"
                  >
                    清空
                  </button>
                </div>
              </div>
              <div className="max-h-[120px] overflow-y-auto rounded-lg border border-[var(--line)] p-2 space-y-1">
                {requirementOptions.map((req) => (
                  <label key={req.id} className="flex items-center gap-2 rounded px-2 py-1 hover:bg-[var(--bg-subtle)] cursor-pointer text-[12px]">
                    <input type="checkbox" checked={selectedReqs.has(req.id)} onChange={() => { const s = new Set(selectedReqs); if (s.has(req.id)) s.delete(req.id); else s.add(req.id); setSelectedReqs(s); }} className="h-3.5 w-3.5 rounded" />
                    <span className="text-[var(--ink-muted)] font-mono">{req.code}</span>
                    <span className="text-[var(--ink)] truncate">{req.title}</span>
                    {req.isHistorical && <span className="text-[10px] text-orange-600 bg-orange-50 px-1.5 py-0.5 rounded">历史</span>}
                  </label>
                ))}
              </div>
            </div>
          )}
          {planType === 'research' && (
            <div>
              <label className="text-[12px] font-medium text-[var(--ink-soft)] mb-1.5 block">
                调研方向 <span className="text-red-500">*</span>
                <span className="text-[10px] text-[var(--ink-muted)] ml-1">至少添加一项</span>
              </label>
              {/* 预设选项 */}
              <div className="flex flex-wrap gap-1.5 mb-2">
                {researchDirectionPresetOptions.map((option) => (
                  <button
                    key={option.title}
                    type="button"
                    disabled={option.disabled}
                    onClick={() => {
                      if (option.disabled) return;
                      setTasks([...tasks, { id: `task-${Date.now()}-${Math.random().toString(36).slice(2, 5)}`, title: option.title, status: 'pending' }]);
                    }}
                    className={`h-6 px-2.5 rounded-md text-[11px] border transition-colors ${option.disabled ? 'cursor-not-allowed border-[var(--accent)] bg-[var(--accent-soft)] text-[var(--accent)] opacity-70' : 'border-dashed border-[var(--line)] text-[var(--ink-soft)] hover:border-[var(--accent)] hover:text-[var(--accent)]'}`}
                  >
                    + {option.title}
                  </button>
                ))}
              </div>
              {false && tasks.length === 0 && (
                <div className="flex flex-wrap gap-1.5 mb-2">
                  {['竞品分析', '用户访谈', '数据调研', '技术可行性分析', '市场调研', '需求分析'].map((preset) => (
                    <button
                      key={preset}
                      type="button"
                      onClick={() => setTasks([...tasks, { id: `task-${Date.now()}-${Math.random().toString(36).slice(2, 5)}`, title: preset, status: 'pending' }])}
                      className="h-6 px-2.5 rounded-md text-[11px] border border-dashed border-[var(--line)] text-[var(--ink-soft)] hover:border-[var(--accent)] hover:text-[var(--accent)] transition-colors"
                    >
                      + {preset}
                    </button>
                  ))}
                </div>
              )}
              <div className="space-y-1.5 mb-2">
                {tasks.map((task, i) => (
                  <div key={task.id} className="flex items-center gap-2 rounded-lg bg-[var(--bg-subtle)] px-3 py-1.5">
                    <span className="flex-1 text-[12px] text-[var(--ink)]">{task.title}</span>
                    <button type="button" onClick={() => setTasks(tasks.filter((_, idx) => idx !== i))} className="text-red-400 hover:text-red-600"><X className="h-3 w-3" /></button>
                  </div>
                ))}
              </div>
              <div className="flex gap-2">
                <input
                  value={newTaskTitle}
                  onChange={(e) => setNewTaskTitle(e.target.value)}
                  onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); if (newTaskTitle.trim()) { setTasks([...tasks, { id: `task-${Date.now()}`, title: newTaskTitle.trim(), status: 'pending' }]); setNewTaskTitle(''); } } }}
                  placeholder="自定义调研方向，回车添加"
                  className="flex-1 h-8 rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 text-[12px] focus:border-[var(--accent)] focus:outline-none"
                />
                <button type="button" onClick={() => { if (newTaskTitle.trim()) { setTasks([...tasks, { id: `task-${Date.now()}`, title: newTaskTitle.trim(), status: 'pending' }]); setNewTaskTitle(''); } }} className="h-8 px-3 rounded-lg text-[12px] font-medium bg-[var(--bg-subtle)] text-[var(--ink-soft)] hover:bg-[var(--line)]">添加</button>
              </div>
              {tasks.length === 0 && (
                <div className="text-[11px] text-red-500 mt-1">请至少添加一项调研方向</div>
              )}
            </div>
          )}
          <div>
            <label className="text-[12px] font-medium text-[var(--ink-soft)] mb-1 block">备注</label>
            <textarea value={remark} onChange={(e) => setRemark(e.target.value)} rows={2} className="w-full rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 py-2 text-[13px] focus:border-[var(--accent)] focus:outline-none resize-none" />
          </div>
          <div className="flex justify-end gap-2 pt-2">
            <button type="button" onClick={onClose} 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 type="submit" className="h-8 px-4 rounded-lg text-[12px] font-medium bg-[var(--accent)] text-white hover:bg-[var(--accent-hover)]">{initial ? '保存' : '创建'}</button>
          </div>
        </form>
      </div>
    </div>
  );
}

function CompleteModal({ plan, onClose, onSubmit }: {
  plan: VersionPlan;
  onClose: () => void;
  onSubmit: (result: PlanResultPayload) => void;
}) {
  const [resultType, setResultType] = useState<'link' | 'file'>('link');
  const [resultTitle, setResultTitle] = useState('');
  const [url, setUrl] = useState('');
  const [fileName, setFileName] = useState('');
  const [fileData, setFileData] = useState('');
  const [prototypeReviewConfirmed, setPrototypeReviewConfirmed] = useState(false);
  const [reviewResult, setReviewResult] = useState<ProductPlanReviewResult>('passed');
  const [reviewFailureTypes, setReviewFailureTypes] = useState<Set<ProductPlanReviewFailureType>>(new Set());
  const [reviewFailureReason, setReviewFailureReason] = useState('');

  const productPlanKind = plan.type === 'product' ? getProductPlanKind(plan) : undefined;
  const isProductDesignPlan = productPlanKind === 'design';
  const isProductReviewPlan = productPlanKind === 'review';

  const handleFile = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;
    setFileName(file.name);
    const reader = new FileReader();
    reader.onload = () => setFileData(reader.result as string);
    reader.readAsDataURL(file);
  };

  const canSubmit = isProductReviewPlan
    ? reviewResult === 'passed' || (reviewFailureTypes.size > 0 && reviewFailureReason.trim().length > 0)
    : isProductDesignPlan
      ? resultTitle.trim().length > 0 && url.trim().length > 0 && prototypeReviewConfirmed
      : resultTitle.trim().length > 0 && (resultType === 'link' ? url.trim().length > 0 : fileData.length > 0);

  const toggleFailureType = (type: ProductPlanReviewFailureType) => {
    const next = new Set(reviewFailureTypes);
    if (next.has(type)) next.delete(type);
    else next.add(type);
    setReviewFailureTypes(next);
  };

  const handleSubmit = () => {
    if (isProductReviewPlan) {
      onSubmit({
        productPlanKind: 'review',
        reviewResult,
        reviewFailureTypes: reviewResult === 'failed' ? Array.from(reviewFailureTypes) : undefined,
        reviewFailureReason: reviewResult === 'failed' ? reviewFailureReason.trim() : undefined,
        resultTitle: PRODUCT_PLAN_REVIEW_RESULT_LABEL[reviewResult],
      });
      return;
    }

    if (isProductDesignPlan) {
      onSubmit({
        productPlanKind: 'design',
        resultType: 'link',
        resultTitle: resultTitle.trim(),
        resultUrl: url.trim(),
        prototypeReviewConfirmed,
      });
      return;
    }

    onSubmit({
      resultType,
      resultTitle: resultTitle.trim(),
      resultUrl: resultType === 'link' ? url.trim() : fileData,
      resultFileName: fileName || undefined,
      resultFileData: resultType === 'file' ? fileData : undefined,
    });
  };

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40" onClick={onClose}>
      <div className="w-full max-w-sm rounded-2xl bg-[var(--bg-card)] border border-[var(--line)] p-5 shadow-[var(--shadow-md)]" onClick={(e) => e.stopPropagation()}>
        <div className="flex items-center justify-between mb-4">
          <h3 className="text-[13px] font-semibold text-[var(--ink)]">{getSubmitActionLabel(plan)}</h3>
          <button onClick={onClose} className="p-1 rounded hover:bg-[var(--bg-subtle)] text-[var(--ink-muted)]"><X className="h-4 w-4" /></button>
        </div>
        <div className="space-y-3">
          {isProductReviewPlan ? (
            <>
              <div>
                <label className="block text-[11px] font-medium text-[var(--ink-soft)] mb-1">评审结论<span className="text-red-500 ml-0.5">*</span></label>
                <div className="grid grid-cols-2 gap-2">
                  {(['passed', 'failed'] as ProductPlanReviewResult[]).map((result) => (
                    <button
                      key={result}
                      type="button"
                      onClick={() => setReviewResult(result)}
                      className={`h-9 rounded-lg border text-[12px] font-medium transition-colors ${reviewResult === result ? 'border-[var(--accent)] bg-[var(--accent-soft)] text-[var(--accent)]' : 'border-[var(--line)] text-[var(--ink-soft)] hover:bg-[var(--bg-subtle)]'}`}
                    >
                      {PRODUCT_PLAN_REVIEW_RESULT_LABEL[result]}
                    </button>
                  ))}
                </div>
              </div>
              {reviewResult === 'failed' && (
                <div className="space-y-2">
                  <div>
                    <label className="block text-[11px] font-medium text-[var(--ink-soft)] mb-1">不通过类型<span className="text-red-500 ml-0.5">*</span></label>
                    <div className="grid grid-cols-2 gap-1.5">
                      {PRODUCT_PLAN_REVIEW_FAILURE_OPTIONS.map((option) => (
                        <label key={option.value} className="flex min-h-8 cursor-pointer items-center gap-1.5 rounded-lg border border-[var(--line)] px-2 py-1 text-[11px] text-[var(--ink-soft)] hover:bg-[var(--bg-subtle)]">
                          <input type="checkbox" checked={reviewFailureTypes.has(option.value)} onChange={() => toggleFailureType(option.value)} className="h-3 w-3 shrink-0 rounded" />
                          <span className="leading-4">{option.label}</span>
                        </label>
                      ))}
                    </div>
                  </div>
                  <div>
                    <label className="block text-[11px] font-medium text-[var(--ink-soft)] mb-1">原因说明<span className="text-red-500 ml-0.5">*</span></label>
                    <textarea
                      value={reviewFailureReason}
                      onChange={(e) => setReviewFailureReason(e.target.value)}
                      rows={3}
                      placeholder="写清楚具体问题、影响范围和建议调整方向"
                      className="w-full rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 py-2 text-[13px] focus:border-[var(--accent)] focus:outline-none resize-none"
                    />
                  </div>
                </div>
              )}
            </>
          ) : (
            <>
              {isProductDesignPlan && (
                <div className="rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-[11px] leading-5 text-amber-800">
                  请确认产品方案评审已通过后再提交原型地址；这里不再上传 Axure 文件，AI 后续会优先读取可访问的原型链接。
                </div>
              )}
              <div>
                <label className="block text-[11px] font-medium text-[var(--ink-soft)] mb-1">成果标题<span className="text-red-500 ml-0.5">*</span></label>
                <input value={resultTitle} onChange={(e) => setResultTitle(e.target.value)} placeholder={isProductDesignPlan ? '如 v1.0 原型地址' : '如 v1.0 产品方案'} className="h-9 w-full rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 text-[13px] focus:border-[var(--accent)] focus:outline-none" />
              </div>
              {!isProductDesignPlan && (
                <div className="flex gap-2">
                  <button type="button" onClick={() => setResultType('link')} className={`h-8 px-3 rounded-lg text-[12px] font-medium border transition-colors ${resultType === 'link' ? 'border-[var(--accent)] bg-[var(--accent-soft)] text-[var(--accent)]' : 'border-[var(--line)] text-[var(--ink-soft)]'}`}>链接</button>
                  <button type="button" onClick={() => setResultType('file')} className={`h-8 px-3 rounded-lg text-[12px] font-medium border transition-colors ${resultType === 'file' ? 'border-[var(--accent)] bg-[var(--accent-soft)] text-[var(--accent)]' : 'border-[var(--line)] text-[var(--ink-soft)]'}`}>文件</button>
                </div>
              )}
              {resultType === 'link' || isProductDesignPlan ? (
                <input value={url} onChange={(e) => setUrl(e.target.value)} placeholder="https://..." className="h-9 w-full rounded-lg border border-[var(--line)] bg-[var(--bg-card)] px-3 text-[13px] focus:border-[var(--accent)] focus:outline-none" />
              ) : (
                <div>
                  <input type="file" onChange={handleFile} className="text-[12px] text-[var(--ink-soft)]" />
                  {fileName && <p className="text-[11px] text-[var(--ink-muted)] mt-1">已选：{fileName}</p>}
                </div>
              )}
              {isProductDesignPlan && (
                <label className="flex items-start gap-2 rounded-lg border border-[var(--line)] bg-[var(--bg-subtle)] px-3 py-2 text-[12px] text-[var(--ink-soft)]">
                  <input
                    type="checkbox"
                    checked={prototypeReviewConfirmed}
                    onChange={(e) => setPrototypeReviewConfirmed(e.target.checked)}
                    className="mt-0.5 h-3.5 w-3.5 rounded"
                  />
                  <span>已确认该产品设计方案评审通过，可以作为后续开发任务和测试用例拆解依据。</span>
                </label>
              )}
            </>
          )}
          <div className="flex justify-end gap-2 pt-2">
            <button onClick={onClose} 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={handleSubmit} disabled={!canSubmit} className="h-8 px-4 rounded-lg text-[12px] font-medium bg-[var(--accent)] text-white hover:bg-[var(--accent-hover)] disabled:opacity-50">确认</button>
          </div>
        </div>
      </div>
    </div>
  );
}
