import { PrismaClient, AuditAction, AuditStatus, RiskLevel, ComplianceLevel, DbOperation } from '@prisma/client';
import { createHash, randomUUID } from 'crypto';

const prisma = new PrismaClient();

function sortObject(obj: any): any {
  if (obj === null || obj === undefined) return obj;
  if (obj instanceof Date) return obj.toISOString();
  if (Array.isArray(obj)) return obj.map(sortObject);
  if (typeof obj !== 'object') return obj;
  const sorted: any = {};
  for (const key of Object.keys(obj).sort()) sorted[key] = sortObject(obj[key]);
  return sorted;
}

function computeHash(record: any): string {
  const { currentHash, signature, createdAt, archivedAt, ...rest } = record;
  return createHash('sha256').update(JSON.stringify(sortObject(rest)), 'utf8').digest('hex');
}

type Sample = {
  who: string;
  module: string;
  action: AuditAction;
  entityType: string;
  what: string;
  why?: string;
  how: string;
  oldValue?: any;
  newValue?: any;
  status?: AuditStatus;
  isFinancial?: boolean;
  isSensitive?: boolean;
  riskLevel?: RiskLevel;
  complianceLevel?: ComplianceLevel;
  duration?: number;
  errorMessage?: string;
  withDbChange?: { table: string; op: DbOperation; fields: string[] };
  withSensitiveOp?: { type: string; description: string; requiresApproval: boolean };
};

const SAMPLES: Sample[] = [
  { who: 'itadmin', module: 'iam', action: 'LOGIN', entityType: 'User', what: '管理员登录', how: 'POST /api/auth/login', duration: 142 },
  { who: 'itadmin', module: 'iam', action: 'CREATE', entityType: 'User', what: '创建用户 zhangsan', how: 'POST /api/users',
    newValue: { username: 'zhangsan', email: 'zhangsan@ff.com', status: 'ACTIVE' }, duration: 87,
    withDbChange: { table: 'platform_iam.user', op: 'INSERT', fields: ['username', 'email', 'status'] } },
  { who: 'itadmin', module: 'iam', action: 'ROLE_CHANGE', entityType: 'User', what: '为 zhangsan 分配 HR_MANAGER 角色',
    how: 'POST /api/users/:id/roles', oldValue: { roles: ['EMPLOYEE'] }, newValue: { roles: ['EMPLOYEE', 'HR_MANAGER'] },
    isSensitive: true, riskLevel: 'HIGH', complianceLevel: 'HIGH', duration: 156,
    withSensitiveOp: { type: 'ROLE_ASSIGNMENT', description: '为用户分配高权限角色', requiresApproval: false } },
  { who: 'zhangsan', module: 'iam', action: 'LOGIN', entityType: 'User', what: '用户登录', how: 'POST /api/auth/login', duration: 98 },
  { who: 'unknown', module: 'iam', action: 'LOGIN_FAILED', entityType: 'User', what: '密码错误登录失败', how: 'POST /api/auth/login',
    status: 'FAILED', errorMessage: 'Invalid credentials', riskLevel: 'HIGH', duration: 45 },
  { who: 'zhangsan', module: 'performance', action: 'CREATE', entityType: 'PerformanceCycle', what: '创建 2026-Q2 绩效周期',
    how: 'POST /api/performance/cycles', newValue: { name: '2026-Q2', startDate: '2026-04-01', endDate: '2026-06-30' }, duration: 203 },
  { who: 'zhangsan', module: 'performance', action: 'UPDATE', entityType: 'PerformanceEvaluation', what: '更新绩效评估打分',
    how: 'PATCH /api/performance/evaluations/:id', oldValue: { score: 3.5 }, newValue: { score: 4.2 }, duration: 76 },
  { who: 'lisi', module: 'approval', action: 'APPROVE', entityType: 'LeaveRequest', what: '批准请假申请',
    how: 'POST /api/approvals/:id/approve', why: '事由合理，余额充足', newValue: { status: 'APPROVED' }, duration: 134 },
  { who: 'lisi', module: 'approval', action: 'REJECT', entityType: 'ExpenseClaim', what: '驳回报销申请',
    how: 'POST /api/approvals/:id/reject', why: '发票不齐', newValue: { status: 'REJECTED' }, duration: 89 },
  { who: 'finance_admin', module: 'finance', action: 'PAYMENT', entityType: 'Payment', what: '支付供应商款项 ¥125,000',
    how: 'POST /api/payments', isFinancial: true, isSensitive: true, riskLevel: 'HIGH', complianceLevel: 'HIGH',
    newValue: { amount: 125000, currency: 'CNY', vendor: 'ACME Corp' }, duration: 412,
    withSensitiveOp: { type: 'PAYMENT_EXECUTION', description: '执行大额付款', requiresApproval: true } },
  { who: 'finance_admin', module: 'finance', action: 'INVOICE_GENERATE', entityType: 'Invoice', what: '生成发票',
    how: 'POST /api/invoices', isFinancial: true, complianceLevel: 'HIGH', duration: 178 },
  { who: 'hr_manager', module: 'hr', action: 'EXPORT', entityType: 'EmployeeRoster', what: '导出员工花名册',
    how: 'GET /api/employees/export', isSensitive: true, riskLevel: 'MEDIUM',
    newValue: { count: 348, format: 'xlsx' }, duration: 1247 },
  { who: 'system', module: 'sync', action: 'IMPORT', entityType: 'DingtalkAttendance', what: '钉钉考勤同步',
    how: 'CRON dingtalk-attendance-sync', newValue: { records: 1024, success: 1019, failed: 5 }, duration: 8932,
    status: 'PARTIAL' },
  { who: 'devops', module: 'system', action: 'CONFIG_CHANGE', entityType: 'SystemConfig', what: '修改邮件服务器配置',
    how: 'PATCH /api/system/config', oldValue: { smtpHost: 'old.smtp.com' }, newValue: { smtpHost: 'new.smtp.com' },
    isSensitive: true, riskLevel: 'HIGH', complianceLevel: 'HIGH', duration: 67,
    withSensitiveOp: { type: 'CONFIG_CHANGE', description: '修改关键系统配置', requiresApproval: true } },
  { who: 'devops', module: 'system', action: 'BACKUP', entityType: 'Database', what: '执行数据库备份',
    how: 'CRON db-backup', newValue: { size: '2.4GB', location: 's3://backup/2026-05-07.sql.gz' }, duration: 184320 },
  { who: 'wangwu', module: 'iam', action: 'PASSWORD_CHANGE', entityType: 'User', what: '修改自己密码',
    how: 'POST /api/users/me/password', isSensitive: true, riskLevel: 'MEDIUM', duration: 234 },
  { who: 'itadmin', module: 'iam', action: 'PASSWORD_RESET', entityType: 'User', what: '重置 wangwu 密码',
    how: 'POST /api/users/:id/reset-password', isSensitive: true, riskLevel: 'HIGH', duration: 156,
    withSensitiveOp: { type: 'PASSWORD_RESET', description: '管理员重置他人密码', requiresApproval: false } },
  { who: 'zhangsan', module: 'document', action: 'DOWNLOAD', entityType: 'Document', what: '下载机密文档',
    how: 'GET /api/documents/:id/download', isSensitive: true, riskLevel: 'MEDIUM',
    newValue: { fileName: 'salary-report-2026Q1.xlsx', size: '127KB' }, duration: 312 },
  { who: 'zhangsan', module: 'document', action: 'SHARE', entityType: 'Document', what: '分享文档给外部',
    how: 'POST /api/documents/:id/share', isSensitive: true, riskLevel: 'HIGH',
    newValue: { sharedWith: 'partner@external.com', permission: 'VIEW' }, duration: 89 },
  { who: 'system', module: 'iam', action: 'BULK_UPDATE', entityType: 'Permission', what: '批量更新权限点',
    how: 'INTERNAL migration-2026-05', newValue: { affectedRows: 47 }, duration: 523,
    withDbChange: { table: 'platform_iam.permission', op: 'UPDATE', fields: ['code', 'description'] } },
  { who: 'lisi', module: 'approval', action: 'WITHDRAW', entityType: 'LeaveRequest', what: '撤回审批',
    how: 'POST /api/approvals/:id/withdraw', duration: 67 },
  { who: 'zhangsan', module: 'iam', action: 'LOGOUT', entityType: 'User', what: '用户登出', how: 'POST /api/auth/logout', duration: 23 },
  { who: 'devops', module: 'deploy', action: 'DEPLOY', entityType: 'Application', what: '部署 v2.4.1 到 UAT',
    how: 'CI/CD pipeline', newValue: { version: 'v2.4.1', env: 'uat', commit: 'd1c0e6f' }, duration: 245000 },
  { who: 'devops', module: 'deploy', action: 'ROLLBACK', entityType: 'Application', what: '回滚 UAT 至 v2.4.0',
    how: 'CI/CD pipeline', isSensitive: true, riskLevel: 'HIGH',
    oldValue: { version: 'v2.4.1' }, newValue: { version: 'v2.4.0' }, duration: 187000,
    withSensitiveOp: { type: 'ROLLBACK', description: '生产/UAT 环境回滚', requiresApproval: true } },
  { who: 'finance_admin', module: 'finance', action: 'FINANCIAL_CLOSE', entityType: 'AccountingPeriod', what: '关闭 2026-04 会计期间',
    how: 'POST /api/finance/close', isFinancial: true, complianceLevel: 'HIGH', duration: 4521 },
];

const SEED_REGION = 'cn';
const SEED_TENANT = 'default';

async function main() {
  // 哈希链按 region+tenantId 分链；seed 写入到 (cn, default) 域，因此只能从同域取 latest，
  // 否则跨域串链会破坏「按 region+tenantId 串链」语义（如历史 region='CN' 与新写 'cn' 互相污染）。
  const existed = await prisma.auditLog.count({ where: { region: SEED_REGION, tenantId: SEED_TENANT } });
  const latest = existed > 0
    ? await prisma.auditLog.findFirst({
        where: { region: SEED_REGION, tenantId: SEED_TENANT },
        orderBy: { when: 'desc' },
        select: { currentHash: true },
      })
    : null;
  if (existed > 0) {
    console.log(`[audit-log seed] (${SEED_REGION}/${SEED_TENANT}) 已存在 ${existed} 条记录，接续哈希链追加 ${SAMPLES.length} 条演示数据`);
  }

  // 取真实的 userId 关联（如果用户存在），否则留 null
  const users = await prisma.user.findMany({ select: { id: true, username: true } }).catch(() => [] as any[]);
  const userMap = new Map(users.map(u => [u.username, u.id]));

  let previousHash = latest?.currentHash ?? 'GENESIS';
  const now = Date.now();
  let dbChangeCount = 0;
  let sensitiveOpCount = 0;

  for (let i = 0; i < SAMPLES.length; i++) {
    const s = SAMPLES[i];
    // 时间倒推：从 30 天前递增到现在，制造时间分布
    const when = new Date(now - (SAMPLES.length - i) * (30 * 24 * 60 * 60 * 1000) / SAMPLES.length);

    const record: any = {
      id: randomUUID(),
      region: SEED_REGION,
      tenantId: SEED_TENANT,
      who: s.who,
      what: s.what,
      when,
      where: '/api',
      why: s.why ?? null,
      how: s.how,
      module: s.module,
      action: s.action,
      entityType: s.entityType,
      entityId: randomUUID(),
      oldValue: s.oldValue ?? null,
      newValue: s.newValue ?? null,
      changes: s.oldValue && s.newValue ? { from: s.oldValue, to: s.newValue } : null,
      userId: userMap.get(s.who) ?? null,
      sessionId: randomUUID(),
      traceId: randomUUID(),
      requestId: randomUUID(),
      ipAddress: `10.0.${(i % 8) + 1}.${100 + i}`,
      userAgent: 'Mozilla/5.0 (seed-script) AppleWebKit/537.36',
      deviceId: null,
      geoLocation: 'CN/Shanghai',
      businessType: null,
      businessKey: null,
      status: s.status ?? 'SUCCESS',
      errorMessage: s.errorMessage ?? null,
      duration: s.duration ?? null,
      isFinancial: s.isFinancial ?? false,
      isSensitive: s.isSensitive ?? false,
      riskLevel: s.riskLevel ?? 'MEDIUM',
      complianceLevel: s.complianceLevel ?? 'MEDIUM',
      retentionYears: s.complianceLevel === 'HIGH' ? 7 : s.complianceLevel === 'LOW' ? 3 : 5,
      previousHash,
    };
    record.currentHash = computeHash(record);
    previousHash = record.currentHash;

    await prisma.auditLog.create({ data: record });

    if (s.withDbChange && record.userId) {
      await prisma.auditDatabaseChangeLog.create({
        data: {
          tableName: s.withDbChange.table,
          operation: s.withDbChange.op,
          recordId: record.entityId,
          oldData: s.oldValue ?? null,
          newData: s.newValue ?? null,
          changedFields: s.withDbChange.fields,
          userId: record.userId,
          auditLogId: record.id,
        },
      });
      dbChangeCount++;
    }
    if (s.withSensitiveOp && record.userId) {
      await prisma.auditSensitiveOperationLog.create({
        data: {
          operationType: s.withSensitiveOp.type,
          description: s.withSensitiveOp.description,
          requiresApproval: s.withSensitiveOp.requiresApproval,
          riskLevel: record.riskLevel,
          mfaVerified: false,
          userId: record.userId,
          auditLogId: record.id,
        },
      });
      sensitiveOpCount++;
    }
  }

  // 完整性检查记录一条
  await prisma.auditIntegrityCheckLog.create({
    data: {
      region: SEED_REGION,
      tenantId: SEED_TENANT,
      checkType: 'HASH_CHAIN',
      startTime: new Date(now - 60_000),
      endTime: new Date(now),
      recordCount: SAMPLES.length,
      passCount: SAMPLES.length,
      failCount: 0,
      status: 'SUCCESS',
    },
  });

  console.log(`[audit-log seed] ✓ 写入 ${SAMPLES.length} 条审计日志`);
  console.log(`[audit-log seed] ✓ 写入 ${dbChangeCount} 条 DB 变更明细（仅 userId 命中真实用户的记录）`);
  console.log(`[audit-log seed] ✓ 写入 ${sensitiveOpCount} 条敏感操作明细`);
  console.log(`[audit-log seed] ✓ 写入 1 条完整性检查记录`);
}

main()
  .catch((e) => {
    console.error('[audit-log seed] 失败:', e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
