import {
  OutlookBootstrapStatus,
  OutlookCancellationSource,
  OutlookManageStatus,
  PrismaClient,
} from '@prisma/client';

type CliOptions = {
  mailboxEmail: string;
  seriesMasterId: string;
  apply: boolean;
  limit?: number;
};

function printHelp() {
  console.log(`
用法:
  npx ts-node ../scripts/backend/data/backfill-outlook-series-child-bindings.ts \\
    --mailbox-email <邮箱> \\
    --series-master-id <Graph SeriesMasterId> [选项]

说明:
  - 默认 dry-run，只预览将补齐的子绑定，不写库
  - 加 --apply 才会执行写入
  - 本脚本仅补齐子绑定，不直接创建子会议；请随后触发一次 Outlook 同步（或等待自动同步）

选项:
  --mailbox-email <邮箱>         必填，目标邮箱
  --series-master-id <ID>        必填，系列主会议 Graph Event ID
  --limit <数字>                 可选，最多处理多少条实例（用于分批），默认不限制
  --apply                        执行写入
  --help                         查看帮助

示例:
  # 1) 预览
  npx ts-node ../scripts/backend/data/backfill-outlook-series-child-bindings.ts \\
    --mailbox-email shengmin.shi@ff.com \\
    --series-master-id AAMk...AAA=

  # 2) 执行补齐
  npx ts-node ../scripts/backend/data/backfill-outlook-series-child-bindings.ts \\
    --mailbox-email shengmin.shi@ff.com \\
    --series-master-id AAMk...AAA= \\
    --apply
`);
}

function parseArgs(argv: string[]): CliOptions {
  if (argv.includes('--help') || argv.includes('-h')) {
    printHelp();
    process.exit(0);
  }

  const getValue = (flag: string) => {
    const index = argv.indexOf(flag);
    if (index < 0) return undefined;
    return argv[index + 1];
  };

  const mailboxEmail = getValue('--mailbox-email')?.trim().toLowerCase();
  const seriesMasterId = getValue('--series-master-id')?.trim();
  if (!mailboxEmail) {
    throw new Error('缺少必填参数: --mailbox-email');
  }
  if (!seriesMasterId) {
    throw new Error('缺少必填参数: --series-master-id');
  }

  const limitRaw = getValue('--limit');
  const limit = limitRaw ? Number(limitRaw) : undefined;
  if (limitRaw && (!Number.isInteger(limit) || Number(limit) <= 0)) {
    throw new Error(`--limit 必须是正整数，当前: ${limitRaw}`);
  }

  return {
    mailboxEmail,
    seriesMasterId,
    apply: argv.includes('--apply'),
    limit,
  };
}

async function main() {
  const options = parseArgs(process.argv.slice(2));
  const prisma = new PrismaClient();

  try {
    const mailbox = await prisma.outlookSyncMailbox.findUnique({
      where: { mailboxEmail: options.mailboxEmail },
      select: { id: true, mailboxEmail: true, isEnabled: true },
    });
    if (!mailbox) {
      throw new Error(`未找到邮箱: ${options.mailboxEmail}`);
    }

    const seriesBinding = await prisma.outlookMeetingBinding.findFirst({
      where: {
        primaryMailboxId: mailbox.id,
        graphEventId: options.seriesMasterId,
        graphEventType: 'seriesMaster',
        manageStatus: OutlookManageStatus.MANAGED,
      },
      select: {
        id: true,
        graphEventId: true,
        primaryMailboxId: true,
        ownerUserId: true,
        ownerEmail: true,
        meetingSeriesId: true,
        syncFrom: true,
      },
    });

    if (!seriesBinding) {
      throw new Error(
        `未找到已纳管的系列主绑定: mailbox=${mailbox.mailboxEmail}, seriesMasterId=${options.seriesMasterId}`,
      );
    }

    const snapshotWhere: any = {
      mailboxId: mailbox.id,
      seriesMasterId: options.seriesMasterId,
      eventType: { in: ['occurrence', 'exception'] },
    };
    if (seriesBinding.syncFrom) {
      snapshotWhere.startTime = { gte: seriesBinding.syncFrom };
    }

    const snapshots = await prisma.outlookEventSnapshot.findMany({
      where: snapshotWhere,
      orderBy: { startTime: 'asc' },
      ...(options.limit ? { take: options.limit } : {}),
      select: {
        graphEventId: true,
        iCalUId: true,
        eventType: true,
        startTime: true,
        title: true,
        isCancelled: true,
      },
    });

    if (snapshots.length === 0) {
      console.log('未找到可补齐的 series 实例快照（可能都早于 syncFrom，或快照缺失）。');
      return;
    }

    const existingBindings = await prisma.outlookMeetingBinding.findMany({
      where: {
        graphEventId: {
          in: snapshots.map((item) => item.graphEventId),
        },
      },
      select: {
        graphEventId: true,
        graphSeriesMasterId: true,
        ownerEmail: true,
        manageStatus: true,
      },
    });
    const existingMap = new Map(existingBindings.map((item) => [item.graphEventId, item]));

    const missing = snapshots.filter((item) => !existingMap.has(item.graphEventId));
    const conflicts = snapshots.filter((item) => {
      const existed = existingMap.get(item.graphEventId);
      return existed && existed.graphSeriesMasterId && existed.graphSeriesMasterId !== options.seriesMasterId;
    });

    console.log('--- 补偿预览 ---');
    console.log(`mailboxEmail: ${mailbox.mailboxEmail}`);
    console.log(`mailboxId: ${mailbox.id}`);
    console.log(`seriesMasterId: ${options.seriesMasterId}`);
    console.log(`seriesBindingId: ${seriesBinding.id}`);
    console.log(`syncFrom: ${seriesBinding.syncFrom?.toISOString() ?? 'null'}`);
    console.log(`snapshotCountInScope: ${snapshots.length}`);
    console.log(`missingChildBindings: ${missing.length}`);
    console.log(`conflictBindings: ${conflicts.length}`);
    console.log(`mode: ${options.apply ? 'APPLY' : 'DRY-RUN'}`);

    if (missing.length > 0) {
      console.log('\n--- 待补齐样本（最多10条）---');
      missing.slice(0, 10).forEach((item, index) => {
        console.log(
          `${index + 1}. graphEventId=${item.graphEventId}, type=${item.eventType}, `
          + `start=${item.startTime?.toISOString() ?? 'null'}, cancelled=${item.isCancelled}, title=${JSON.stringify(item.title)}`,
        );
      });
    }

    if (conflicts.length > 0) {
      console.log('\n--- 冲突样本（最多10条）---');
      conflicts.slice(0, 10).forEach((item, index) => {
        const existed = existingMap.get(item.graphEventId)!;
        console.log(
          `${index + 1}. graphEventId=${item.graphEventId}, existingSeriesMaster=${existed.graphSeriesMasterId}, `
          + `existingOwner=${existed.ownerEmail || 'unknown'}, existingStatus=${existed.manageStatus}`,
        );
      });
    }

    if (!options.apply) {
      console.log('\n当前为 dry-run，未写入。确认无误后加 --apply 执行。');
      return;
    }

    const now = new Date();
    const syncFrom = seriesBinding.syncFrom || now;
    let created = 0;
    await prisma.$transaction(async (tx) => {
      for (const item of missing) {
        await tx.outlookMeetingBinding.create({
          data: {
            primaryMailboxId: seriesBinding.primaryMailboxId,
            graphEventId: item.graphEventId,
            iCalUId: item.iCalUId || item.graphEventId,
            graphSeriesMasterId: options.seriesMasterId,
            graphEventType: item.eventType as any,
            manageStatus: OutlookManageStatus.MANAGED,
            bootstrapStatus: null,
            bootstrapError: null,
            bootstrapUpdatedAt: now,
            ownerUserId: seriesBinding.ownerUserId || null,
            ownerEmail: seriesBinding.ownerEmail || null,
            meetingSeriesId: seriesBinding.meetingSeriesId || null,
            syncFrom,
            cancellationSource: item.isCancelled
              ? OutlookCancellationSource.CANCELLED_BY_ORGANIZER
              : null,
            lastSyncedAt: now,
          },
        });
        created += 1;
      }

      await tx.outlookMeetingBinding.update({
        where: { id: seriesBinding.id },
        data: {
          bootstrapStatus: OutlookBootstrapStatus.QUEUED,
          bootstrapError: null,
          bootstrapUpdatedAt: now,
        },
      });
    });

    console.log('\n--- 执行结果 ---');
    console.log(`createdChildBindings: ${created}`);
    console.log('已将系列主绑定标记为 QUEUED。请触发一次 Outlook 同步（或等待自动同步）以回填子会议与参会人。');
  } finally {
    await prisma.$disconnect();
  }
}

main().catch((error) => {
  console.error('脚本执行失败:', error);
  process.exit(1);
});
