'use client';

import { useState, useMemo, useEffect } from 'react';
import { Plus, ClipboardCheck, Trash2 } from 'lucide-react';
import { useTestCaseStore } from '@/stores/useTestCaseStore';
import { useBugStore } from '@/stores/useBugStore';
import { useDevTaskStore } from '@/stores/useDevTaskStore';
import { useRequirementStore } from '@/stores/useRequirementStore';
import { useAuthStore } from '@/stores/useAuthStore';
import { useTaskCategoryStore } from '@/stores/useTaskCategoryStore';
import { TestCaseRow } from './TestCaseRow';
import { TestCaseCreateModal } from './TestCaseCreateModal';
import { TestCaseDetailDrawer } from './TestCaseDetailDrawer';
import { BugCreateModal } from '@/components/bug/BugCreateModal';
import { aggregateTestCaseHours, calcTestProgress, canStartNextTestRound, copyTestCaseToRound, getNextTestRoundNo, getRequirementDeliveryStatus, getTestCaseRoundNo, TEST_CASE_STATUS_LABEL, testCaseIntervals } from '@/lib/test-case';
import { calcTwoMetrics } from '@/lib/work-hours';
import { Pagination, usePagination } from '@/components/Pagination';
import { FilterSelect } from '@/components/FilterSelect';
import { SearchInput, matchTitleOrNo } from '@/components/SearchInput';
import { useDebouncedValue } from '@/hooks/useDebouncedValue';
import { orderByRequirementForGrouping } from '@/lib/requirement-grouping';
import { buildEffortSummaryMetrics, sumPositiveHours } from '@/lib/effort-summary';
import type { Bug } from '@/lib/bug';
import type { DevTask } from '@/lib/dev-task';
import type { Requirement } from '@/lib/requirement';
import type { TestCase } from '@/lib/test-case';
import type { TestCaseStatus } from '@/lib/test-case';

interface Props {
  versionId: string;
  requirementIds: string[];
  readOnly?: boolean;
  versionCases?: TestCase[];
  versionBugs?: Bug[];
  versionDevTasks?: DevTask[];
  versionRequirements?: Requirement[];
}

const NO_REQUIREMENT_GROUP_PREFIX = '__no_requirement__';

function getTestCaseGroupKey(testCase: { requirementId?: string; requirementName?: string }): string {
  return testCase.requirementId || `${NO_REQUIREMENT_GROUP_PREFIX}${testCase.requirementName || '未命名需求'}`;
}

function getNoRequirementGroupName(groupKey: string): string {
  return groupKey.slice(NO_REQUIREMENT_GROUP_PREFIX.length) || '未命名需求';
}

export function TestCaseTab({
  versionId,
  requirementIds,
  readOnly = false,
  versionCases: scopedVersionCases,
  versionBugs: scopedVersionBugs,
  versionDevTasks: scopedVersionDevTasks,
  versionRequirements,
}: Props) {
  const { testCases, fetchTestCases, createTestCases, deleteTestCase } = useTestCaseStore();
  const { bugs, fetchBugs } = useBugStore();
  const { tasks: devTasks } = useDevTaskStore();
  const { requirements } = useRequirementStore();
  const user = useAuthStore((s) => s.user);
  const { categories, fetchCategories } = useTaskCategoryStore();

  useEffect(() => {
    if (!scopedVersionCases) fetchTestCases();
  }, [fetchTestCases, scopedVersionCases]);
  useEffect(() => {
    if (!scopedVersionBugs) fetchBugs();
  }, [fetchBugs, scopedVersionBugs]);
  useEffect(() => { fetchCategories(); }, [fetchCategories]);

  const reqIdSet = useMemo(() => new Set(requirementIds), [requirementIds]);
  const fallbackVersionCases = useMemo(
    () => testCases.filter((c) => c.versionId === versionId),
    [testCases, versionId],
  );
  const versionCases = scopedVersionCases ?? fallbackVersionCases;
  const rounds = useMemo(
    () => Array.from(new Set(versionCases.map((testCase) => getTestCaseRoundNo(testCase)))).sort((a, b) => a - b),
    [versionCases],
  );
  const [activeRound, setActiveRound] = useState(1);
  useEffect(() => {
    if (rounds.length === 0) {
      if (activeRound !== 1) setActiveRound(1);
      return;
    }
    if (!rounds.includes(activeRound)) setActiveRound(rounds[rounds.length - 1]);
  }, [rounds, activeRound]);
  const activeRoundCases = useMemo(
    () => versionCases.filter((testCase) => getTestCaseRoundNo(testCase) === activeRound),
    [versionCases, activeRound],
  );
  const firstRoundCases = useMemo(
    () => versionCases.filter((testCase) => getTestCaseRoundNo(testCase) === 1),
    [versionCases],
  );
  const fallbackVersionBugs = useMemo(
    () => bugs.filter((bug) => bug.versionId === versionId),
    [bugs, versionId],
  );
  const versionBugs = scopedVersionBugs ?? fallbackVersionBugs;

  const fallbackVersionDevTasks = useMemo(
    () => devTasks.filter((t) => t.versionId === versionId || (!t.versionId && reqIdSet.has(t.requirementId))),
    [devTasks, reqIdSet, versionId],
  );
  const versionDevTasks = scopedVersionDevTasks ?? fallbackVersionDevTasks;

  const stats = calcTestProgress(activeRoundCases, versionBugs);
  const { actual: tcActualHours } = aggregateTestCaseHours(versionCases);
  const { manhours: tcManhours } = useMemo(() => calcTwoMetrics(testCaseIntervals(versionCases)), [versionCases]);
  const effortMetrics = useMemo(
    () => buildEffortSummaryMetrics({
      aiEstimateHours: sumPositiveHours(versionCases, (testCase) => testCase.aiEstimateHours),
      estimateHours: sumPositiveHours(versionCases, (testCase) => testCase.estimateHours),
      actualHours: tcActualHours,
      manhours: tcManhours,
    }),
    [versionCases, tcActualHours, tcManhours],
  );
  const canCreateNextRound = useMemo(() => canStartNextTestRound(versionCases), [versionCases]);
  const nextRoundNo = useMemo(() => getNextTestRoundNo(versionCases), [versionCases]);

  const [filterAssignee, setFilterAssignee] = useState('');
  const [filterStatus, setFilterStatus] = useState('');
  const [keyword, setKeyword] = useState('');
  const debouncedKeyword = useDebouncedValue(keyword, 300);

  const filteredCases = useMemo(() => {
    let result = activeRoundCases;
    if (filterAssignee) result = result.filter((c) => c.assigneeId === filterAssignee);
    if (filterStatus) result = result.filter((c) => c.status === filterStatus);
    if (debouncedKeyword) result = result.filter((c) => matchTitleOrNo({ title: c.title, no: c.caseNo }, debouncedKeyword));
    return result;
  }, [activeRoundCases, filterAssignee, filterStatus, debouncedKeyword]);

  const orderedCases = useMemo(
    () => orderByRequirementForGrouping(filteredCases, requirementIds, (testCase) => testCase.requirementId),
    [filteredCases, requirementIds],
  );

  const { paged, page, setPage, total, pageSize, setPageSize } = usePagination(orderedCases, 20);

  const [showCreate, setShowCreate] = useState(false);
  const [selectedCaseId, setSelectedCaseId] = useState<string | null>(null);
  const [bugForCaseId, setBugForCaseId] = useState<string | null>(null);

  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());

  const toggleSelect = (id: string) => {
    if (readOnly) return;
    const next = new Set(selectedIds);
    if (next.has(id)) next.delete(id); else next.add(id);
    setSelectedIds(next);
  };
  const handleBatchDelete = () => {
    if (readOnly) return;
    if (selectedIds.size === 0) return;
    const hasBug = Array.from(selectedIds).some((id) => bugs.some((b) => b.testCaseId === id));
    if (hasBug) {
      alert('选中的用例中有关联 Bug 的用例，无法删除。请先取消关联 Bug 的用例选择。');
      return;
    }
    if (!confirm(`确定删除选中的 ${selectedIds.size} 个测试用例？`)) return;
    selectedIds.forEach((id) => deleteTestCase(id));
    setSelectedIds(new Set());
  };
  const handleRoundChange = (roundNo: number) => {
    setActiveRound(roundNo);
    setSelectedIds(new Set());
    setPage(1);
  };
  const handleStartNewRound = () => {
    if (readOnly) return;
    if (!canCreateNextRound) return;
    const operator = user?.name || '系统';
    createTestCases(firstRoundCases.map((testCase) => copyTestCaseToRound(testCase, nextRoundNo, operator)));
    handleRoundChange(nextRoundNo);
  };

  const groupedByReq = useMemo(() => {
    const map = new Map<string, typeof paged>();
    for (const c of paged) {
      const key = getTestCaseGroupKey(c);
      const list = map.get(key) || [];
      list.push(c);
      map.set(key, list);
    }
    return map;
  }, [paged]);

  const visibleRequirements = versionRequirements ?? requirements;
  const requirementMap = useMemo(() => new Map(visibleRequirements.map((r) => [r.id, r])), [visibleRequirements]);
  const categoryMap = useMemo(() => new Map(categories.map((c) => [c.id, c])), [categories]);
  const categoryLabelWidthEm = useMemo(
    () => Math.max(4, ...categories.map((category) => category.name.length)) + 1,
    [categories],
  );
  const bugCountByCase = useMemo(() => {
    const map = new Map<string, number>();
    for (const b of versionBugs) map.set(b.testCaseId, (map.get(b.testCaseId) ?? 0) + 1);
    return map;
  }, [versionBugs]);

  const assignees = useMemo(() => Array.from(new Set(activeRoundCases.map((c) => c.assigneeId).filter(Boolean) as string[])), [activeRoundCases]);
  const hasFilter = !!(filterAssignee || filterStatus || debouncedKeyword);

  return (
    <div className="space-y-3">
      <div className="flex items-center gap-2 px-4 py-2.5 rounded-lg bg-[var(--bg-subtle)] border border-[var(--line)] flex-wrap">
        <ClipboardCheck className="h-3.5 w-3.5 text-emerald-500 shrink-0" />
        <span className="text-[12px] font-medium text-[var(--ink)] shrink-0">{stats.completionRate}%</span>
        <div className="h-1.5 w-20 rounded-full bg-[var(--bg)] overflow-hidden shrink-0">
          <div className="h-full rounded-full bg-emerald-500" style={{ width: `${stats.completionRate}%` }} />
        </div>
        <span className="text-[11px] text-[var(--ink-muted)] shrink-0">{stats.total}例 · 通过{stats.passed} · 不通过{stats.failed}</span>
        <span className="text-[11px] text-[var(--ink-muted)] shrink-0">无 Bug 通过率 {stats.passRate}%</span>
        {effortMetrics.map((metric) => (
          <span key={metric.label} className="text-[11px] text-[var(--ink-muted)] shrink-0">
            {metric.label} <span className="tabular-nums text-[var(--ink)]">{metric.value}</span>
          </span>
        ))}
        <FilterSelect
          value={String(activeRound)}
          onChange={(value) => handleRoundChange(Number(value))}
          options={(rounds.length > 0 ? rounds : [1]).map((roundNo) => ({ value: String(roundNo), label: `第${roundNo}轮` }))}
          showAllOption={false}
        />

        <span className="w-px h-4 bg-[var(--line)] mx-1 shrink-0" />

        <SearchInput value={keyword} onChange={(v) => { setKeyword(v); setPage(1); }} placeholder="搜索标题/编号" />
        <FilterSelect
          value={filterAssignee || 'all'}
          onChange={(value) => { setFilterAssignee(value === 'all' ? '' : value); setPage(1); }}
          options={[
            ...(user?.name ? [{ value: user.name, label: '我的' }] : []),
            ...assignees.filter((a) => a !== user?.name).map((a) => ({ value: a, label: a })),
          ]}
          allLabel="负责人"
        />
        <FilterSelect
          value={filterStatus || 'all'}
          onChange={(value) => { setFilterStatus(value === 'all' ? '' : value); setPage(1); }}
          options={(Object.entries(TEST_CASE_STATUS_LABEL) as [TestCaseStatus, string][]).map(([value, label]) => ({ value, label }))}
          allLabel="状态"
        />
        {hasFilter && <button onClick={() => { setFilterAssignee(''); setFilterStatus(''); setKeyword(''); setPage(1); }} className="text-[10px] text-[var(--accent)] hover:underline shrink-0">清除</button>}

        <div className="ml-auto flex items-center gap-2 shrink-0">
          {selectedIds.size > 0 && !readOnly && (
            <button onClick={handleBatchDelete} className="flex items-center gap-1 h-6 px-2 rounded text-[11px] font-medium bg-red-500 text-white hover:bg-red-600">
              <Trash2 className="h-3 w-3" />删除{selectedIds.size}项
            </button>
          )}
          {!readOnly && (
            <>
              <button
                onClick={handleStartNewRound}
                disabled={!canCreateNextRound}
                title={canCreateNextRound ? `复制第 1 轮用例，开启第 ${nextRoundNo} 轮测试` : '最新一轮测试用例全部测完后才能开启新一轮'}
                className="flex items-center gap-1 h-6 px-2.5 rounded text-[11px] font-medium bg-emerald-600 text-white hover:bg-emerald-700 disabled:opacity-50 disabled:cursor-not-allowed"
              >
                <Plus className="h-3 w-3" />开启新一轮测试
              </button>
              <button onClick={() => setShowCreate(true)} className="flex items-center gap-1 h-6 px-2.5 rounded text-[11px] font-medium bg-[var(--accent)] text-white hover:bg-[var(--accent-hover)]">
                <Plus className="h-3 w-3" />新建
              </button>
            </>
          )}
        </div>
      </div>

      {filteredCases.length === 0 ? (
        <div className="rounded-xl border border-dashed border-[var(--line)] bg-[var(--bg-card)] p-12 text-center">
          <p className="text-[13px] text-[var(--ink-muted)]">{hasFilter ? '没有匹配的用例' : '暂无测试用例'}</p>
          {!hasFilter && !readOnly && <button onClick={() => setShowCreate(true)} className="mt-3 text-[12px] text-[var(--accent)] hover:underline">创建第一个用例</button>}
        </div>
      ) : (
        Array.from(groupedByReq.entries()).map(([reqId, cases]) => {
          const isNoRequirementGroup = reqId.startsWith(NO_REQUIREMENT_GROUP_PREFIX);
          const req = isNoRequirementGroup ? null : requirementMap.get(reqId);
          const noRequirementName = isNoRequirementGroup ? getNoRequirementGroupName(reqId) : '';
          const reqPassed = cases.filter((c) => c.status === 'passed').length;
          const deliveryStatus = req ? getRequirementDeliveryStatus(req.id, versionDevTasks) : null;
          return (
            <div key={reqId} className="rounded-lg border border-[var(--line)] bg-[var(--bg-card)] overflow-hidden">
              <div className="flex items-center bg-[var(--bg-subtle)] border-b border-[var(--line)]">
                {!readOnly && (
                  <div className="pl-4 flex items-center">
                    <input type="checkbox" checked={cases.every((c) => selectedIds.has(c.id))} onChange={() => { const ids = cases.map((c) => c.id); const allSel = ids.every((id) => selectedIds.has(id)); const next = new Set(selectedIds); if (allSel) ids.forEach((id) => next.delete(id)); else ids.forEach((id) => next.add(id)); setSelectedIds(next); }} className="h-3.5 w-3.5 rounded border-[var(--line)]" />
                  </div>
                )}
                <div className="flex flex-1 min-w-0 items-center gap-2 px-4 py-2">
                  <span className="h-2 w-2 shrink-0" />
                  <span className="w-16 min-w-0 shrink-0 truncate text-[11px] font-mono text-[var(--ink-muted)]" title={isNoRequirementGroup ? '无需求ID' : req?.code || '通用'}>
                    {isNoRequirementGroup ? '无需求ID' : req?.code || '通用'}
                  </span>
                  <span className="text-[12px] font-medium text-[var(--ink)] flex-1 truncate">
                    {isNoRequirementGroup ? noRequirementName : req?.title || '未关联需求'}
                  </span>
                  {deliveryStatus && (
                    <span className={`inline-flex h-5 w-14 shrink-0 items-center justify-center rounded px-1.5 text-[10px] font-medium whitespace-nowrap ${
                      deliveryStatus === 'submitted'
                        ? 'bg-emerald-50 text-emerald-600 border border-emerald-100'
                        : 'bg-orange-50 text-orange-600 border border-orange-100'
                    }`}>
                      {deliveryStatus === 'submitted' ? '已提测' : '待提测'}
                    </span>
                  )}
                  <span className="text-[11px] text-[var(--ink-muted)]">{reqPassed}/{cases.length} 通过</span>
                </div>
              </div>
              {cases.map((c) => (
                <div key={c.id} className="flex items-center">
                  {!readOnly && (
                    <div className="pl-4 flex items-center">
                      <input type="checkbox" checked={selectedIds.has(c.id)} onChange={() => toggleSelect(c.id)} className="h-3.5 w-3.5 rounded border-[var(--line)]" onClick={(e) => e.stopPropagation()} />
                    </div>
                  )}
                  <div className="flex-1 min-w-0">
                    <TestCaseRow testCase={c} category={categoryMap.get(c.categoryId)} categoryLabelWidthEm={categoryLabelWidthEm} bugCount={bugCountByCase.get(c.id) ?? 0} onClick={() => setSelectedCaseId(c.id)} />
                  </div>
                </div>
              ))}
            </div>
          );
        })
      )}

      {total > 20 && <Pagination total={total} page={page} pageSize={pageSize} onChange={setPage} onPageSizeChange={setPageSize} />}

      {showCreate && !readOnly && <TestCaseCreateModal versionId={versionId} requirementIds={requirementIds} roundNo={activeRound} onClose={() => setShowCreate(false)} />}
      {selectedCaseId && <TestCaseDetailDrawer testCaseId={selectedCaseId} readOnly={readOnly} onClose={() => setSelectedCaseId(null)} onCreateBug={(id) => { if (!readOnly) setBugForCaseId(id); }} />}
      {bugForCaseId && !readOnly && <BugCreateModal testCaseId={bugForCaseId} onClose={() => setBugForCaseId(null)} />}
    </div>
  );
}
