import fs from 'node:fs';
import path from 'node:path';
import {
  compareVersions,
  fetchNpmPackageMetadata,
  formatDateToMinute,
  resolveProjectRoot,
} from './tfds-version-utils.mjs';
import { getSkillSyncStatus, readTfdsLock, TFDS_LOCK_REL_PATH } from './tfds-lock.mjs';
import {
  analyzeUpgradeImpact,
  loadLocalComponentsIndex,
} from './tfds-upgrade-impact.mjs';

/** 有新版本时，展示在 latest 版本号后的引导文案（Skill 展示给用户时须保留） */
export const TFDS_LATEST_VERSION_HINT = '推荐升级至最新版 Skill，以使用最新组件样式与规范';

export function formatVersionUpgradeNotice(localVersion, latestVersion) {
  return `新版本 v ${localVersion} → v ${latestVersion}（${TFDS_LATEST_VERSION_HINT}）`;
}

/**
 * @typedef {object} TfdsUpdateCheckResult
 * @property {number} exitCode
 * @property {boolean} ok
 * @property {string} status up-to-date | update-available | ahead | network-skipped | error
 * @property {string} packageName
 * @property {string} localVersion
 * @property {string|null} latestVersion
 * @property {boolean} updateAvailable
 * @property {string|null} [networkError]
 */

/**
 * @param {object} options
 * @param {string} options.pkgRoot
 * @param {string} [options.projectRoot]
 * @param {string} options.skillName
 * @param {string} [options.setupCommand]
 * @param {boolean} [options.analyzeImpact=true]
 */
export async function runTfdsUpdateCheck({
  pkgRoot,
  projectRoot: projectRootOpt,
  skillName,
  setupCommand,
  analyzeImpact = true,
}) {
  const projectRoot = resolveProjectRoot(projectRootOpt);
  const packageJsonPath = path.join(pkgRoot, 'package.json');
  let localPkg;

  try {
    localPkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
  } catch (error) {
    return buildErrorResult({
      message: '无法读取本地 package.json',
      detail: error?.message || String(error),
      path: packageJsonPath,
    });
  }

  const packageName = localPkg.name;
  const localVersion = localPkg.version;

  if (!packageName?.startsWith('@tfdesign/') || !localVersion) {
    return buildErrorResult({
      message: '当前脚本不在有效的 @tfdesign/* 包内',
      packageName,
      localVersion,
    });
  }

  const upgradeCommand = `npm install ${packageName}@latest --save`;
  const checkScriptRel = `node_modules/${packageName}/scripts/check-tfds-update.mjs`;
  const localIndex = loadLocalComponentsIndex(pkgRoot, skillName);
  const skillSync = getSkillSyncStatus({
    projectRoot,
    packageName,
    localVersion,
    skillName,
  });
  const lockPath = path.join(projectRoot, TFDS_LOCK_REL_PATH);
  const lockEntry = readTfdsLock(projectRoot)?.packages?.[packageName] || null;

  /** @type {Record<string, unknown>} */
  const base = {
    ok: true,
    packageName,
    localVersion,
    localPublishedAt: null,
    latestVersion: null,
    latestPublishedAt: null,
    updateAvailable: false,
    upgradeCommand,
    setupCommand: setupCommand || null,
    checkScript: checkScriptRel,
    lockFile: fs.existsSync(lockPath) ? TFDS_LOCK_REL_PATH : null,
    lockEntry,
    skillSync,
    packageChanges: null,
    projectImpact: null,
    recommendation: null,
    networkError: null,
  };

  let metadata;
  try {
    metadata = await fetchNpmPackageMetadata(packageName);
  } catch (error) {
    base.status = 'network-skipped';
    base.networkError = error?.message || String(error);
    base.recommendation =
      '暂时无法连接 npm registry，已跳过线上版本检测。可继续使用当前版本；网络恢复后请重新执行检测脚本。';
    return {
      ...base,
      exitCode: 0,
    };
  }

  const latestVersion = metadata?.['dist-tags']?.latest || null;
  base.localPublishedAt = formatDateToMinute(metadata?.time?.[localVersion]);
  base.latestVersion = latestVersion;
  base.latestPublishedAt = latestVersion ? formatDateToMinute(metadata?.time?.[latestVersion]) : null;

  if (!latestVersion) {
    base.status = 'network-skipped';
    base.recommendation = '已连接 npm registry，但未读取到 latest 版本，请稍后重试。';
    return { ...base, exitCode: 0 };
  }

  const versionState = compareVersions(localVersion, latestVersion);

  if (versionState > 0) {
    base.status = 'ahead';
    base.recommendation = '当前本地版本高于 npm latest，可能是预发布或内部测试包。';
    return { ...base, exitCode: 0 };
  }

  if (versionState === 0) {
    base.status = 'up-to-date';
    base.recommendation = skillSync.inSync
      ? '当前 npm 与 Skill 快照均为 latest，可继续生成页面。'
      : `npm 已是 latest，但 Skill 快照可能滞后：${skillSync.staleReason}。建议重新 npm i 触发 postinstall 同步 Skill。`;
    return { ...base, exitCode: 0 };
  }

  base.status = 'update-available';
  base.updateAvailable = true;
  base.latestVersionHint = TFDS_LATEST_VERSION_HINT;
  base.versionNotice = formatVersionUpgradeNotice(localVersion, latestVersion);

  if (analyzeImpact) {
    const impact = await analyzeUpgradeImpact({
      projectRoot,
      packageName,
      skillName,
      localVersion,
      latestVersion,
      localIndex,
    });
    base.packageChanges = {
      generatedAtFrom: impact.packageChanges.generatedAtFrom,
      generatedAtTo: impact.packageChanges.generatedAtTo,
      summaryFrom: impact.packageChanges.summaryFrom,
      summaryTo: impact.packageChanges.summaryTo,
      indexFetchError: impact.packageChanges.indexFetchError || null,
      totals: {
        updated: impact.packageChanges.updated.length,
        added: impact.packageChanges.added.length,
        removed: impact.packageChanges.removed.length,
      },
      updated: impact.packageChanges.updated,
      added: impact.packageChanges.added,
      removed: impact.packageChanges.removed,
    };
    base.projectImpact = {
      hasExistingUsage: impact.hasExistingUsage,
      usedSymbols: impact.usedSymbols,
      affectedComponents: impact.affectedComponents,
      affectedFiles: impact.affectedFiles,
      hasProjectImpact: impact.hasProjectImpact,
      willAutoModifyPages: impact.willAutoModifyPages,
      summary: impact.summary,
    };
  }

  base.recommendation = buildRecommendation(base);

  return {
    ...base,
    exitCode: 1,
  };
}

function buildRecommendation(result) {
  const lines = [
    result.versionNotice || `检测到新版本：v ${result.localVersion} → v ${result.latestVersion}。`,
    TFDS_LATEST_VERSION_HINT,
    '升级 npm 只会更新依赖、theme.css 与 IDE Skill，不会自动修改已有页面源码。',
  ];
  if (result.projectImpact?.hasProjectImpact) {
    lines.push('你的项目中已有页面使用了会在新版本中变化的组件，升级前请先阅读 projectImpact.affectedComponents。');
  } else {
    lines.push('当前项目预期受影响较小，可按需选择升级后再生成。');
  }
  lines.push(`升级命令：${result.upgradeCommand}`);
  if (result.setupCommand) {
    lines.push(`或：${result.setupCommand}`);
  }
  return lines.join(' ');
}

/**
 * @param {Record<string, unknown>} result
 */
export function printTfdsUpdateCheckHuman(result) {
  console.log('\n╔══════════════════════════════════════════════════════╗');
  console.log('║        TFDS NPM 版本更新检测                         ║');
  console.log('╚══════════════════════════════════════════════════════╝');

  if (result.status === 'error') {
    console.log(`\n✗ ${result.message}`);
    if (result.detail) console.log(`  ${result.detail}`);
    console.log('');
    return;
  }

  console.log(`\n  包名：${result.packageName}`);
  console.log(`  当前版本：v ${result.localVersion}`);
  console.log(`  当前版本发布时间：${result.localPublishedAt || '未知'}`);
  console.log(`  线上 latest：v ${result.latestVersion || '未知'}`);
  console.log(`  latest 发布时间：${result.latestPublishedAt || '未知'}`);

  if (result.skillSync) {
    console.log(`\n  Skill 同步：${result.skillSync.inSync ? '✓ 与 npm 一致' : `⚠ ${result.skillSync.staleReason}`}`);
    if (result.lockFile) console.log(`  版本锁：${result.lockFile}`);
  }

  if (result.networkError) {
    console.log(`\n⚠ 无法连接 npm registry：${result.networkError}`);
    console.log(`  ${result.recommendation}\n`);
    return;
  }

  if (result.status === 'up-to-date') {
    console.log(`\n✓ ${result.recommendation}\n`);
    return;
  }

  if (result.status === 'ahead') {
    console.log(`\n✓ ${result.recommendation}\n`);
    return;
  }

  if (result.status !== 'update-available') return;

  console.log('\n⚠ 检测到 TFDS 有新版本。');
  if (result.versionNotice) {
    console.log(`  ${result.versionNotice}`);
  }
  printPackageChangesHuman(result.packageChanges);
  printProjectImpactHuman(result.projectImpact);

  console.log('\n  升级保护：');
  console.log('    • 更新 npm 包不会自动修改你的已有页面源码。');
  console.log('    • 若 projectImpact 列出受影响组件，仅表示「日后按新版生成/迁移」可能不一致。');
  console.log('    • 只有你明确确认后，AI 才允许按新版样式迁移已有界面。');
  console.log('\n  建议更新命令：');
  console.log(`    ${result.upgradeCommand}`);
  if (result.setupCommand) {
    console.log('  或重新执行一键安装：');
    console.log(`    ${result.setupCommand}`);
  }
  console.log('');
}

function printPackageChangesHuman(packageChanges) {
  if (!packageChanges) return;
  console.log('\n  ── 新版本组件/规范变更（packageChanges）──');
  if (packageChanges.summaryTo) {
    console.log(`  索引摘要：${packageChanges.summaryTo}`);
  }
  if (packageChanges.indexFetchError) {
    console.log(`  ⚠ 未能拉取 latest 组件索引：${packageChanges.indexFetchError}`);
    console.log('  仍可升级 npm，但请稍后在 TFDS 平台或 changelog 查看详细差异。');
    return;
  }
  const { totals } = packageChanges;
  console.log(
    `  统计：更新 ${totals.updated} · 新增 ${totals.added} · 移除 ${totals.removed}`,
  );
  const show = (label, items) => {
    if (!items?.length) return;
    console.log(`\n  ${label}（最多展示 12 条）：`);
    for (const item of items.slice(0, 12)) {
      console.log(`    • ${item.name} [${item.changedSections?.join('、') || item.changeType}]`);
      if (item.description) console.log(`      ${String(item.description).slice(0, 80)}`);
    }
    if (items.length > 12) console.log(`    … 另有 ${items.length - 12} 项，见 --json 完整输出`);
  };
  show('有规则/Props/示例变化的组件', packageChanges.updated);
  show('新增', packageChanges.added);
  show('移除', packageChanges.removed);
}

function printProjectImpactHuman(projectImpact) {
  if (!projectImpact) return;
  console.log('\n  ── 对你现有项目的影响（projectImpact）──');
  console.log(`  ${projectImpact.summary}`);
  console.log(`  升级后是否会自动改页面：${projectImpact.willAutoModifyPages ? '是' : '否（仅更新依赖与 Skill）'}`);
  if (!projectImpact.hasExistingUsage) return;
  console.log(`  项目已 import：${projectImpact.usedSymbols.join('、') || '（无）'}`);
  if (!projectImpact.affectedComponents?.length) {
    console.log('  已使用的组件在新版索引中未发现变化，已有页面预期不受影响。');
    return;
  }
  console.log('\n  可能受新版规范影响的组件与文件：');
  for (const item of projectImpact.affectedComponents.slice(0, 15)) {
    console.log(`    • ${item.name}（${item.changedSections.join('、')}）`);
    console.log(`      文件：${item.usedInFiles.join('、')}`);
  }
  if (projectImpact.affectedComponents.length > 15) {
    console.log(`    … 另有 ${projectImpact.affectedComponents.length - 15} 个组件，见 --json`);
  }
}

function buildErrorResult({ message, detail, path: filePath, packageName, localVersion }) {
  return {
    ok: false,
    status: 'error',
    exitCode: 2,
    message,
    detail,
    path: filePath,
    packageName,
    localVersion,
  };
}
