import {
  buildRiskInsightDisplaySignature,
  buildRiskInsightSignature,
  findLatestRiskInsightForVersion,
  getReusableInsight,
} from './xiaobao-risk-ai';
import type { XiaobaoRiskInsight, XiaobaoRiskInsightCacheItem } from './xiaobao-risk-cache';
import type { RiskReason, XiaobaoVersionRisk } from './xiaobao-risk';
import { sanitizeRiskInsight } from './xiaobao-warning-view';

interface AttachXiaobaoRiskSuggestionInput {
  insights: XiaobaoRiskInsightCacheItem[];
  pendingInsightKeys: string[];
  pendingInsightAttempts?: Record<string, string>;
  pendingInsightVisibleMs?: number;
  now?: Date;
}

const DEFAULT_PENDING_INSIGHT_VISIBLE_MS = 3 * 60 * 1000;

const RISK_LEVEL_LABEL: Record<XiaobaoVersionRisk['riskLevel'], string> = {
  on_track: '按期',
  attention: '需关注',
  at_risk: '有风险',
  likely_delayed: '大概率延期',
  blocked: '阻塞',
};

export function buildXiaobaoRiskInsightPendingKey(risk: XiaobaoVersionRisk): string {
  return `${risk.versionId}:${buildRiskInsightDisplaySignature(risk)}`;
}

export function attachXiaobaoRiskSuggestion(
  risk: XiaobaoVersionRisk,
  input: AttachXiaobaoRiskSuggestionInput,
): XiaobaoVersionRisk {
  const pendingKey = buildXiaobaoRiskInsightPendingKey(risk);
  const isUpdating = isFreshPendingInsight(pendingKey, input);
  const reusable = getReusableInsight(input.insights, risk);
  if (reusable) {
    return {
      ...risk,
      aiInsight: sanitizeRiskInsight(reusable.insight),
      aiInsightSource: 'current_ai',
      aiInsightUpdating: false,
    };
  }

  const latest = findLatestRiskInsightForVersion(input.insights, risk.versionId);
  if (latest) {
    return {
      ...risk,
      aiInsight: sanitizeRiskInsight(latest.insight),
      aiInsightSource: 'previous_ai',
      aiInsightUpdating: isUpdating,
    };
  }

  return {
    ...risk,
    aiInsight: buildRuleBasedRiskInsight(risk, input.now),
    aiInsightSource: 'rule',
    aiInsightUpdating: isUpdating,
  };
}

function isFreshPendingInsight(pendingKey: string, input: AttachXiaobaoRiskSuggestionInput): boolean {
  if (!input.pendingInsightKeys.includes(pendingKey)) return false;
  const requestedAt = input.pendingInsightAttempts?.[pendingKey];
  if (!requestedAt) return true;

  const requestedTime = new Date(requestedAt).getTime();
  const nowTime = (input.now ?? new Date()).getTime();
  if (!Number.isFinite(requestedTime) || !Number.isFinite(nowTime)) return false;

  const visibleMs = input.pendingInsightVisibleMs ?? DEFAULT_PENDING_INSIGHT_VISIBLE_MS;
  return nowTime - requestedTime < visibleMs;
}

export function buildRuleBasedRiskInsight(risk: XiaobaoVersionRisk, now = new Date()): XiaobaoRiskInsight {
  const firstReason = risk.reasons[0];
  const why = risk.reasons.length > 0
    ? risk.reasons.slice(0, 4).map((reason) => reason.detail || reason.title)
    : [risk.trend.summary || '当前版本存在规则层识别到的发布风险。'];
  const forecastDate = formatDate(risk.forecastReleaseDate);
  const expectedDate = formatDate(risk.expectedReleaseDate);
  const forecast = risk.delayDays > 0
    ? `按当前剩余工作量和风险信号，预计较期望发版日期${expectedDate ? `（${expectedDate}）` : ''}延期约 ${risk.delayDays} 天，可发窗口约为 ${forecastDate || '重新评估后确认'}。`
    : `按当前规则预测，版本仍有风险需要收敛；预计可发窗口为 ${forecastDate || expectedDate || '待补齐计划后确认'}。`;

  return sanitizeRiskInsight({
    summary: `${risk.versionName} 当前风险分 ${risk.riskScore}，状态为${RISK_LEVEL_LABEL[risk.riskLevel]}。${firstReason?.title ? `主要关注：${firstReason.title}。` : ''}`,
    why,
    forecast,
    recommendedReleaseWindow: buildReleaseWindow(risk),
    suggestedActions: buildRuleActions(risk),
    ownerHints: buildOwnerHints(risk),
    generatedAt: now.toISOString(),
  });
}

function buildReleaseWindow(risk: XiaobaoVersionRisk): string | undefined {
  const forecastDate = formatDate(risk.forecastReleaseDate);
  if (!forecastDate) return undefined;
  if (risk.delayDays > 0) return `建议优先以 ${forecastDate} 作为新的候选发版窗口，并在关键风险关闭后再确认。`;
  return `建议继续以 ${forecastDate} 附近作为候选发版窗口，但需要先完成当前风险项收敛。`;
}

function buildRuleActions(risk: XiaobaoVersionRisk): string[] {
  const actions = risk.reasons.flatMap(reasonToActions);
  const unique = Array.from(new Set(actions));
  if (unique.length > 0) return unique.slice(0, 4);
  return ['确认剩余任务、测试失败、Bug 和阻塞项的负责人及预计完成时间。'];
}

function reasonToActions(reason: RiskReason): string[] {
  switch (reason.key) {
    case 'critical_bug':
      return ['优先收敛 P1 或致命 Bug，明确修复人、复测人和关闭时间。'];
    case 'failed_test':
      return ['安排测试负责人复测失败用例，并同步失败原因和修复进展。'];
    case 'blocked_work':
      return ['先解除阻塞项，无法当天解除的需要明确替代方案或延期影响。'];
    case 'forecast_delay':
    case 'remaining_work':
      return ['按剩余工作量重排今天到发版日前的完成顺序，先处理影响发版的主链路事项。'];
    case 'silent_risk':
      return ['要求未更新的负责人补充今日日报或活动证据，避免静默风险继续扩大。'];
    default:
      return reason.detail ? [`跟进：${reason.detail}`] : [];
  }
}

function buildOwnerHints(risk: XiaobaoVersionRisk): string[] {
  const hints: string[] = [];
  if (risk.signals.unfinishedCount > 0) hints.push(`仍有 ${risk.signals.unfinishedCount} 个未完成事项，需要逐项确认负责人。`);
  if (risk.signals.openBugCount > 0) hints.push(`仍有 ${risk.signals.openBugCount} 个未关闭 Bug，需要确认修复和复测节奏。`);
  if (risk.signals.silentRiskCount > 0) hints.push(`存在 ${risk.signals.silentRiskCount} 个静默风险，需要负责人补充进展。`);
  return hints;
}

function formatDate(value: string | null | undefined): string | undefined {
  if (!value) return undefined;
  const raw = value.trim();
  if (!raw) return undefined;
  if (/^\d{4}-\d{2}-\d{2}/.test(raw)) return raw.slice(0, 10);
  const time = new Date(raw).getTime();
  if (!Number.isFinite(time)) return undefined;
  return new Date(time).toISOString().slice(0, 10);
}
