import { api } from './api';
import type { Bug, BugSeverity, BugStatus } from './bug';
import type { DevTask, DevTaskStatus, Reference } from './dev-task';
import type { Priority } from './derive';
import type { Requirement, RequirementStatus, SourceType } from './requirement';
import type { TestCase, TestCaseStatus } from './test-case';
import type { VersionDataScope } from './version-data-scope';
import type {
  PlanTask,
  VersionPlan,
  VersionPlanLog,
  VersionPlanRequirementCoverage,
} from './version-plan';

type V22DateValue = string | Date | null | undefined;

interface V22VersionRow {
  id: string;
  productId: string;
  projectId?: string | null;
  name: string;
  releaseDate?: V22DateValue;
  createdAt?: V22DateValue;
  updatedAt?: V22DateValue;
}

interface V22RequirementRow {
  id: string;
  productId: string;
  projectId?: string | null;
  versionId?: string | null;
  code: string;
  title: string;
  description?: string | null;
  status?: string | null;
  priority?: number | string | null;
  type?: string | null;
  sourceType?: string | null;
  sourceTarget?: string | null;
  platform?: string | null;
  creatorId?: string | null;
  createdAt?: V22DateValue;
  updatedAt?: V22DateValue;
}

interface V22VersionPlanRow {
  id: string;
  versionId: string;
  type: string;
  title: string;
  status?: string | null;
  ownerId?: string | null;
  expectedStartAt?: V22DateValue;
  expectedEndAt?: V22DateValue;
  actualStartAt?: V22DateValue;
  completedAt?: V22DateValue;
  resultUrl?: string | null;
  requirementCoverage?: unknown;
  logs?: unknown;
  createdAt?: V22DateValue;
  updatedAt?: V22DateValue;
}

interface V22DevTaskRow {
  id: string;
  versionId: string;
  requirementId?: string | null;
  categoryId?: string | null;
  code: string;
  title: string;
  description?: string | null;
  status?: string | null;
  priority?: number | string | null;
  assigneeId?: string | null;
  creatorId?: string | null;
  isBlocked?: boolean | null;
  blockReason?: string | null;
  expectedStartAt?: V22DateValue;
  expectedEndAt?: V22DateValue;
  startDate?: V22DateValue;
  completedAt?: V22DateValue;
  estimateHours?: number | null;
  aiEstimateHours?: number | null;
  references?: unknown;
  aiDraft?: boolean | null;
  aiDraftAt?: V22DateValue;
  createdAt?: V22DateValue;
  updatedAt?: V22DateValue;
}

interface V22TestCaseRow {
  id: string;
  versionId: string;
  requirementId?: string | null;
  categoryId?: string | null;
  code: string;
  title: string;
  description?: string | null;
  status?: string | null;
  roundNo?: number | null;
  priority?: number | string | null;
  assigneeId?: string | null;
  creatorId?: string | null;
  plannedTestAt?: V22DateValue;
  plannedEndAt?: V22DateValue;
  startedAt?: V22DateValue;
  completedAt?: V22DateValue;
  estimateHours?: number | null;
  aiEstimateHours?: number | null;
  references?: unknown;
  aiDraft?: boolean | null;
  aiDraftAt?: V22DateValue;
  createdAt?: V22DateValue;
  updatedAt?: V22DateValue;
}

interface V22BugRow {
  id: string;
  versionId: string;
  testCaseId?: string | null;
  code: string;
  title: string;
  description?: string | null;
  status?: string | null;
  severity?: string | null;
  priority?: number | string | null;
  assigneeId?: string | null;
  reporterId?: string | null;
  plannedFixAt?: V22DateValue;
  resolvedAt?: V22DateValue;
  closedAt?: V22DateValue;
  resolution?: string | null;
  createdAt?: V22DateValue;
  updatedAt?: V22DateValue;
}

interface V22VersionDetailResponse {
  version: V22VersionRow;
  requirements: V22RequirementRow[];
  versionPlans: V22VersionPlanRow[];
  devTasks: V22DevTaskRow[];
  testCases: V22TestCaseRow[];
  bugs: V22BugRow[];
}

export interface V22VersionDetailData {
  version: V22VersionRow;
  scope: VersionDataScope;
}

export interface V22RequirementsQuery {
  productId: string;
  projectId?: string;
  versionId?: string;
  status?: string;
  priority?: string;
  type?: string;
  q?: string;
  sort?: string;
  cursor?: string;
  limit?: number;
}

export interface V22RequirementsPage {
  items: Requirement[];
  nextCursor?: string;
}

export interface V22WorkspaceData {
  versionPlans: VersionPlan[];
  devTasks: DevTask[];
  testCases: TestCase[];
  bugs: Bug[];
}

export interface V22XiaobaoWarningQuery {
  userId?: string;
  manager?: boolean;
}

export interface V22XiaobaoWarningSummary {
  versionId: string;
  riskLevel: string;
  riskScore: number;
  confidence: number;
  forecastReleaseDate?: string;
  riskSignature: string;
  summary: unknown;
  dirty?: boolean;
  recomputedAt?: string;
  updatedAt?: string;
}

export async function loadV22VersionDetailData(versionId: string): Promise<V22VersionDetailData> {
  const response = await api.get<V22VersionDetailResponse>(
    `/v2.2/versions/${encodeURIComponent(versionId)}/detail-data`,
  );
  return {
    version: response.version,
    scope: buildScope(response),
  };
}

export async function loadV22RequirementsPage(query: V22RequirementsQuery): Promise<V22RequirementsPage> {
  const response = await api.get<{ items: V22RequirementRow[]; nextCursor?: string }>(
    `/v2.2/requirements?${queryString(query)}`,
  );
  return {
    items: response.items.map(mapRequirement),
    nextCursor: response.nextCursor,
  };
}

export async function loadV22WorkspaceData(userId: string): Promise<V22WorkspaceData> {
  const response = await api.get<{
    versionPlans: V22VersionPlanRow[];
    devTasks: V22DevTaskRow[];
    testCases: V22TestCaseRow[];
    bugs: V22BugRow[];
  }>(`/v2.2/workspace?${queryString({ userId })}`);
  return {
    versionPlans: response.versionPlans.map(mapVersionPlan),
    devTasks: response.devTasks.map(mapDevTask),
    testCases: response.testCases.map(mapTestCase),
    bugs: response.bugs.map(mapBug),
  };
}

export async function loadV22XiaobaoWarnings(
  query: V22XiaobaoWarningQuery,
): Promise<V22XiaobaoWarningSummary[]> {
  const response = await api.get<Array<Omit<V22XiaobaoWarningSummary, 'forecastReleaseDate' | 'recomputedAt' | 'updatedAt'> & {
    forecastReleaseDate?: V22DateValue;
    recomputedAt?: V22DateValue;
    updatedAt?: V22DateValue;
  }>>(`/v2.2/xiaobao-warning?${queryString({
    userId: query.userId,
    manager: query.manager ? 'true' : undefined,
  })}`);
  return response.map((row) => ({
    ...row,
    forecastReleaseDate: optionalIso(row.forecastReleaseDate),
    recomputedAt: optionalIso(row.recomputedAt),
    updatedAt: optionalIso(row.updatedAt),
  }));
}

function buildScope(response: V22VersionDetailResponse): VersionDataScope {
  const requirements = response.requirements.map(mapRequirement);
  const requirementIds = requirements.map((requirement) => requirement.id);
  const requirementIdSet = new Set(requirementIds);
  const plans = response.versionPlans.map(mapVersionPlan);
  const plansByType: VersionDataScope['plansByType'] = { research: [], product: [], ui: [] };
  for (const plan of plans) {
    plansByType[plan.type].push(plan);
  }

  return {
    requirements,
    requirementIds,
    requirementIdSet,
    plans,
    plansByType,
    devTasks: response.devTasks.map(mapDevTask),
    testCases: response.testCases.map(mapTestCase),
    bugs: response.bugs.map(mapBug),
    overtimeRecords: [],
  };
}

function mapRequirement(row: V22RequirementRow): Requirement {
  return {
    id: row.id,
    code: row.code,
    title: row.title,
    description: row.description ?? '',
    productId: row.productId,
    projectId: row.projectId ?? '',
    versionId: row.versionId ?? undefined,
    sourceType: toSourceType(row.sourceType),
    sourceTarget: row.sourceTarget ?? '',
    platforms: splitCsv(row.platform),
    typeId: row.type ?? '',
    status: toRequirementStatus(row.status),
    priority: toPriority(row.priority),
    effort: 'M',
    creator: row.creatorId ?? '',
    createdAt: requiredIso(row.createdAt),
  };
}

function mapVersionPlan(row: V22VersionPlanRow): VersionPlan {
  const coverage = asArray<VersionPlanRequirementCoverage>(row.requirementCoverage);
  return {
    id: row.id,
    versionId: row.versionId,
    type: toPlanType(row.type),
    title: row.title,
    owner: row.ownerId ?? '',
    startTime: requiredIso(row.expectedStartAt),
    endTime: requiredIso(row.expectedEndAt),
    status: toPlanStatus(row.status),
    tasks: [],
    completedRequirementIds: coverage
      .filter((item) => item?.status === 'completed')
      .map((item) => item.requirementId)
      .filter(Boolean),
    linkedRequirementIds: coverage.map((item) => item?.requirementId).filter(Boolean),
    requirementCoverage: coverage,
    logs: asArray<VersionPlanLog>(row.logs),
    resultUrl: row.resultUrl ?? undefined,
    actualStartAt: optionalIso(row.actualStartAt),
    createdAt: requiredIso(row.createdAt),
    completedAt: optionalIso(row.completedAt),
    addedBy: row.ownerId ?? '',
  };
}

function mapDevTask(row: V22DevTaskRow): DevTask {
  return {
    id: row.id,
    taskNo: row.code,
    versionId: row.versionId,
    requirementId: row.requirementId ?? '',
    title: row.title,
    description: row.description ?? '',
    categoryId: row.categoryId ?? '',
    assigneeId: row.assigneeId ?? '',
    priority: toPriority(row.priority),
    expectedStartAt: requiredIso(row.expectedStartAt),
    expectedEndAt: requiredIso(row.expectedEndAt),
    estimateHours: row.estimateHours ?? undefined,
    aiEstimateHours: row.aiEstimateHours ?? undefined,
    actualStartAt: optionalIso(row.startDate),
    actualEndAt: optionalIso(row.completedAt),
    status: toDevTaskStatus(row.status),
    isBlocked: row.isBlocked ?? false,
    blockReason: row.blockReason ?? undefined,
    references: asArray<Reference>(row.references),
    aiDraft: row.aiDraft ?? false,
    aiDraftAt: optionalIso(row.aiDraftAt),
    createdBy: row.creatorId ?? '',
    createdAt: requiredIso(row.createdAt),
    updatedAt: requiredIso(row.updatedAt),
  };
}

function mapTestCase(row: V22TestCaseRow): TestCase {
  return {
    id: row.id,
    caseNo: row.code,
    versionId: row.versionId,
    requirementId: row.requirementId ?? undefined,
    roundNo: row.roundNo ?? 1,
    title: row.title,
    description: row.description ?? '',
    categoryId: row.categoryId ?? '',
    priority: toPriority(row.priority),
    assigneeId: row.assigneeId ?? undefined,
    status: toTestCaseStatus(row.status),
    estimateHours: row.estimateHours ?? undefined,
    aiEstimateHours: row.aiEstimateHours ?? undefined,
    plannedTestAt: optionalIso(row.plannedTestAt),
    plannedEndAt: optionalIso(row.plannedEndAt),
    startedAt: optionalIso(row.startedAt),
    completedAt: optionalIso(row.completedAt),
    references: asArray<Reference>(row.references),
    aiDraft: row.aiDraft ?? false,
    aiDraftAt: optionalIso(row.aiDraftAt),
    createdBy: row.creatorId ?? '',
    createdAt: requiredIso(row.createdAt),
    updatedAt: requiredIso(row.updatedAt),
  };
}

function mapBug(row: V22BugRow): Bug {
  return {
    id: row.id,
    bugNo: row.code,
    versionId: row.versionId,
    testCaseId: row.testCaseId ?? '',
    title: row.title,
    description: row.description ?? '',
    severity: toBugSeverity(row.severity),
    priority: toPriority(row.priority),
    reportedBy: row.reporterId ?? '',
    assigneeId: row.assigneeId ?? '',
    status: toBugStatus(row.status),
    resolvedAt: optionalIso(row.resolvedAt),
    closedAt: optionalIso(row.closedAt),
    resolution: row.resolution ?? undefined,
    plannedFixAt: optionalIso(row.plannedFixAt),
    createdAt: requiredIso(row.createdAt),
    updatedAt: requiredIso(row.updatedAt),
  };
}

function queryString<T extends object>(values: T): string {
  const params = new URLSearchParams();
  Object.entries(values).forEach(([key, value]) => {
    if (value === undefined || value === '') return;
    params.set(key, String(value));
  });
  return params.toString();
}

function requiredIso(value: V22DateValue): string {
  return optionalIso(value) ?? '';
}

function optionalIso(value: V22DateValue): string | undefined {
  if (!value) return undefined;
  if (value instanceof Date) return value.toISOString();
  const trimmed = value.trim();
  if (!trimmed) return undefined;
  if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) return `${trimmed}T00:00:00.000Z`;
  const parsed = new Date(trimmed);
  if (Number.isFinite(parsed.getTime())) return parsed.toISOString();
  return trimmed;
}

function splitCsv(value?: string | null): string[] {
  if (!value) return [];
  return value.split(',').map((item) => item.trim()).filter(Boolean);
}

function asArray<T>(value: unknown): T[] {
  return Array.isArray(value) ? value as T[] : [];
}

function toPriority(value: number | string | null | undefined): Priority {
  if (typeof value === 'string') {
    const normalized = value.trim().toUpperCase();
    if (/^P[0-4]$/.test(normalized)) return normalized as Priority;
    const parsed = Number(normalized);
    if (Number.isFinite(parsed)) return toPriority(parsed);
  }
  const rank = typeof value === 'number' && Number.isFinite(value) ? Math.floor(value) : 2;
  return `P${Math.max(0, Math.min(4, rank))}` as Priority;
}

function toSourceType(value?: string | null): SourceType {
  const allowed: SourceType[] = ['customer', 'internal', 'operation', 'aftersale', 'market', 'competitor', 'management'];
  return allowed.includes(value as SourceType) ? value as SourceType : 'internal';
}

function toRequirementStatus(value?: string | null): RequirementStatus {
  const allowed: RequirementStatus[] = ['pending_review', 'adopted', 'rejected', 'planned', 'developing', 'testing', 'released', 'closed'];
  return allowed.includes(value as RequirementStatus) ? value as RequirementStatus : 'pending_review';
}

function toPlanType(value: string): VersionPlan['type'] {
  return value === 'research' || value === 'ui' ? value : 'product';
}

function toPlanStatus(value?: string | null): VersionPlan['status'] {
  if (value === 'in_progress' || value === 'completed') return value;
  return 'pending';
}

function toDevTaskStatus(value?: string | null): DevTaskStatus {
  if (value === 'in_progress' || value === 'testing' || value === 'submitted') return value;
  return 'todo';
}

function toTestCaseStatus(value?: string | null): TestCaseStatus {
  if (value === 'running' || value === 'passed' || value === 'failed' || value === 'blocked') return value;
  return 'pending';
}

function toBugStatus(value?: string | null): BugStatus {
  if (value === 'fixing' || value === 'fixed' || value === 'verifying' || value === 'closed' || value === 'rejected') {
    return value;
  }
  return 'open';
}

function toBugSeverity(value?: string | null): BugSeverity {
  if (value === 'critical' || value === 'major' || value === 'trivial') return value;
  return 'minor';
}
