import type { Priority } from './derive';
import { calcActualElapsedHours, calcWorkHours, formatWorkHours, type TimeInterval } from './work-hours';

export type DevTaskStatus = 'todo' | 'in_progress' | 'testing' | 'submitted';

export type ReferenceType = 'requirement' | 'prototype_note' | 'external';

export interface Reference {
  type: ReferenceType;
  id: string;
  label: string;
  url?: string;
}

export interface DevTask {
  id: string;
  taskNo: string;
  versionId?: string;
  requirementId: string;
  requirementName?: string;
  title: string;
  description?: string;
  categoryId: string;
  assigneeId: string;
  reviewerId?: string;
  priority: Priority;

  expectedStartAt: string;
  expectedEndAt: string;
  estimateHours?: number;
  aiEstimateHours?: number;
  actualStartAt?: string;
  actualEndAt?: string;

  status: DevTaskStatus;
  isBlocked: boolean;
  blockReason?: string;
  blockedById?: string;
  predecessorIds?: string[];
  riskLevel?: 'low' | 'medium' | 'high';
  delayReason?: string;
  overdueVersionReason?: string;
  references?: Reference[];
  aiDraft?: boolean;
  aiDraftAt?: string;
  createdBy: string;
  createdAt: string;
  updatedAt: string;
}

export const DEV_TASK_STATUS_LABEL: Record<DevTaskStatus, string> = {
  todo: '待开发',
  in_progress: '开发中',
  testing: '自测',
  submitted: '已提测',
};

export const DEV_TASK_STATUS_COLOR: Record<DevTaskStatus, string> = {
  todo: 'bg-zinc-100 text-zinc-600',
  in_progress: 'bg-blue-50 text-blue-600',
  testing: 'bg-purple-50 text-purple-600',
  submitted: 'bg-emerald-50 text-emerald-600',
};

export const STATUS_PROGRESS: Record<DevTaskStatus, number> = {
  todo: 0,
  in_progress: 50,
  testing: 80,
  submitted: 100,
};

export const ALLOWED_TRANSITIONS: Record<DevTaskStatus, DevTaskStatus[]> = {
  todo: ['in_progress'],
  in_progress: ['testing'],
  testing: ['submitted', 'in_progress'],
  submitted: [],
};

export function canTransition(from: DevTaskStatus, to: DevTaskStatus): boolean {
  return ALLOWED_TRANSITIONS[from].includes(to);
}

export function calcTaskProgress(task: DevTask): number {
  return STATUS_PROGRESS[task.status];
}

export function calcGroupProgress(tasks: DevTask[]): number {
  if (tasks.length === 0) return 0;
  const totalEstimate = tasks.reduce((sum, t) => sum + getEstimateHours(t), 0);
  if (totalEstimate === 0) {
    const sum = tasks.reduce((s, t) => s + STATUS_PROGRESS[t.status], 0);
    return Math.round(sum / tasks.length);
  }
  const weighted = tasks.reduce((sum, t) => sum + getEstimateHours(t) * STATUS_PROGRESS[t.status], 0);
  return Math.round(weighted / totalEstimate);
}

export function formatHours(hours: number): string {
  return formatWorkHours(hours);
}

export function getEstimateHours(task: DevTask): number {
  if (typeof task.estimateHours === 'number' && task.estimateHours > 0) {
    return roundEffortHours(task.estimateHours);
  }
  if (typeof task.aiEstimateHours === 'number' && task.aiEstimateHours > 0) {
    return roundEffortHours(task.aiEstimateHours);
  }
  if (!task.expectedStartAt || !task.expectedEndAt) return 0;
  return calcWorkHours(task.expectedStartAt, task.expectedEndAt);
}

function roundEffortHours(hours: number): number {
  return Number(hours.toFixed(2));
}

export function needsDevTaskClaim(task: Pick<DevTask, 'assigneeId'>): boolean {
  return !task.assigneeId?.trim();
}

export function hasDevTaskPlan(task: Pick<DevTask, 'expectedStartAt' | 'expectedEndAt'>): boolean {
  if (!task.expectedStartAt || !task.expectedEndAt) return false;
  const start = new Date(task.expectedStartAt).getTime();
  const end = new Date(task.expectedEndAt).getTime();
  return Number.isFinite(start) && Number.isFinite(end) && end > start;
}

export function canStartDevTask(task: Pick<DevTask, 'assigneeId' | 'expectedStartAt' | 'expectedEndAt'>): boolean {
  return !needsDevTaskClaim(task) && hasDevTaskPlan(task);
}

export function getActualHours(task: DevTask, now: Date = new Date()): number {
  if (!task.actualStartAt) return 0;
  const end = task.actualEndAt ?? (task.status === 'submitted' ? task.updatedAt : now.toISOString());
  return calcActualElapsedHours(task.actualStartAt, end);
}

export interface AggregatedHours {
  estimate: number;
  actual: number;
}

export function aggregateDevTaskHours(tasks: DevTask[], now: Date = new Date()): AggregatedHours {
  let estimate = 0;
  let actual = 0;
  for (const t of tasks) {
    estimate += getEstimateHours(t);
    actual += getActualHours(t, now);
  }
  return {
    estimate: Math.round(estimate * 2) / 2,
    actual: Math.round(actual * 2) / 2,
  };
}

export function aggregateActualHoursByAssignee(
  tasks: DevTask[],
  now: Date = new Date(),
): Array<{ assigneeId: string; actualHours: number; taskCount: number }> {
  const map = new Map<string, { actualHours: number; taskCount: number }>();
  for (const t of tasks) {
    const h = getActualHours(t, now);
    if (h <= 0 && t.status !== 'submitted') continue;
    const cur = map.get(t.assigneeId) || { actualHours: 0, taskCount: 0 };
    cur.actualHours += h;
    cur.taskCount += 1;
    map.set(t.assigneeId, cur);
  }
  return Array.from(map.entries())
    .map(([assigneeId, v]) => ({
      assigneeId,
      actualHours: Math.round(v.actualHours * 2) / 2,
      taskCount: v.taskCount,
    }))
    .sort((a, b) => b.actualHours - a.actualHours);
}

/**
 * 抽取每条已开干任务的 [actualStartAt, actualEndAt ?? now] 时间区间
 * 用于双口径耗时统计（calcTwoMetrics）
 */
export function devTaskIntervals(tasks: DevTask[], now: Date = new Date()): TimeInterval[] {
  const out: TimeInterval[] = [];
  const nowIso = now.toISOString();
  for (const t of tasks) {
    if (!t.actualStartAt) continue;
    out.push({ start: t.actualStartAt, end: t.actualEndAt ?? (t.status === 'submitted' ? t.updatedAt : nowIso) });
  }
  return out;
}

export function generateTaskNo(existingTasks: DevTask[]): string {
  const maxNum = existingTasks.reduce((max, t) => {
    const num = parseInt(t.taskNo.replace('DEV-', ''), 10);
    return isNaN(num) ? max : Math.max(max, num);
  }, 0);
  return `DEV-${String(maxNum + 1).padStart(3, '0')}`;
}

export function isLegacyTask(t: any): boolean {
  if (!t || typeof t !== 'object') return false;
  return (
    'startDate' in t ||
    'dueDate' in t ||
    'completedAt' in t ||
    'actualHours' in t ||
    'overdueReason' in t
  );
}

/**
 * 兼容函数：按纯小时差计算耗时（保留给 PlanTab/TestCase 体系使用）
 * DevTask 体系应改用 getActualHours/getEstimateHours 走 calcWorkHours
 */
export function calcActualHoursByDates(startDate?: string, completedAt?: string): number {
  if (!startDate) return 0;
  const end = completedAt || new Date().toISOString();
  const startMs = new Date(startDate).getTime();
  const endMs = new Date(end).getTime();
  if (isNaN(startMs) || isNaN(endMs) || endMs < startMs) return 0;
  const diffHours = (endMs - startMs) / (1000 * 60 * 60);
  return Math.round(diffHours * 2) / 2;
}
