import { PrismaClient } from '@prisma/client';
import * as bcrypt from 'bcryptjs';
import { seedCatalog } from './seed-catalog';
import { ensureUserInviteCode } from '../../shared/common/invite-code.util';

export const DEMO_ACCOUNTS = [
  'admin / Admin@123',
  'matchadmin / MatchAdmin@123',
  'financeadmin / FinanceAdmin@123',
  'support1 / Support@123',
  'agent1 / Agent@123',
  'player1 / Player@123',
] as const;

export const PRODUCTION_SEED_ACCOUNTS = [
  'admin / Admin@123',
] as const;

export type SeedMode = 'dev' | 'production';

export type RunSeedOptions = {
  mode?: SeedMode;
};

export function resolveSeedMode(options?: RunSeedOptions): SeedMode {
  if (options?.mode) return options.mode;
  if (process.env.SEED_MODE === 'dev') return 'dev';
  if (process.env.SEED_MODE === 'production') return 'production';
  return process.env.NODE_ENV === 'production' ? 'production' : 'dev';
}

export function resolveSeedAccounts(mode: SeedMode): readonly string[] {
  return mode === 'production' ? PRODUCTION_SEED_ACCOUNTS : DEMO_ACCOUNTS;
}

let prisma: PrismaClient;

async function seedRolesAndConfig() {
  const superAdminRole = await prisma.role.upsert({
    where: { code: 'SUPER_ADMIN' },
    create: { code: 'SUPER_ADMIN', name: 'Super Admin', description: 'Full access' },
    update: {},
  });

  const permCodes = [
    'users.create', 'users.view', 'users.reset_password', 'agents.create', 'agents.view', 'agents.credit',
    'wallet.deposit', 'wallet.withdraw', 'matches.manage', 'settlement.confirm',
    'settlement.resettle', 'cashback.confirm', 'content.manage', 'reports.view',
    'bets.view', 'settings.manage', 'settings.reset_database', 'audit.view',
    'deposit.manage', 'deposit.review',
  ];

  const permIds = new Map<string, bigint>();
  for (const code of permCodes) {
    const perm = await prisma.permission.upsert({
      where: { code },
      create: { code, name: code, module: code.split('.')[0] },
      update: {},
    });
    permIds.set(code, perm.id);
    await prisma.rolePermission.upsert({
      where: { roleId_permissionId: { roleId: superAdminRole.id, permissionId: perm.id } },
      create: { roleId: superAdminRole.id, permissionId: perm.id },
      update: {},
    });
  }

  async function ensureRole(code: string, name: string, permissions: string[]) {
    const role = await prisma.role.upsert({
      where: { code },
      create: { code, name, description: name },
      update: { name },
    });
    for (const p of permissions) {
      const pid = permIds.get(p);
      if (!pid) continue;
      await prisma.rolePermission.upsert({
        where: { roleId_permissionId: { roleId: role.id, permissionId: pid } },
        create: { roleId: role.id, permissionId: pid },
        update: {},
      });
    }
    return role;
  }

  const matchAdminRole = await ensureRole('MATCH_ADMIN', 'Match Admin', [
    'matches.manage', 'settlement.confirm', 'content.manage', 'bets.view', 'reports.view', 'audit.view',
  ]);
  const financeAdminRole = await ensureRole('FINANCE_ADMIN', 'Finance Admin', [
    'wallet.deposit', 'wallet.withdraw', 'cashback.confirm', 'agents.view', 'agents.credit',
    'users.view', 'users.create', 'deposit.manage', 'deposit.review',
    'reports.view', 'bets.view', 'audit.view',
  ]);
  const supportRole = await ensureRole('SUPPORT', 'Support', [
    'users.view', 'users.reset_password', 'bets.view', 'reports.view', 'audit.view',
  ]);

  const defaultBettingLimits = [
    ['bet.min_stake', '1', '最小单注金额'],
    ['bet.max_stake_single', '50000', '单关最大投注额'],
    ['bet.max_stake_parlay', '20000', '串关最大投注额'],
    ['bet.max_payout_single', '500000', '单关最高派彩'],
    ['bet.max_payout_parlay', '1000000', '串关最高派彩'],
    ['bet.daily_stake_limit', '200000', '玩家每日投注上限'],
  ] as const;
  for (const [key, value, desc] of defaultBettingLimits) {
    await prisma.systemConfig.upsert({
      where: { configKey: key },
      create: { configKey: key, configValue: value, description: desc },
      update: {},
    });
  }

  return { superAdminRole, matchAdminRole, financeAdminRole, supportRole };
}

async function seedAdminUser(superAdminRole: { id: bigint }) {
  const adminPassword = process.env.ADMIN_INITIAL_PASSWORD ?? 'Admin@123';
  const hash = await bcrypt.hash(adminPassword, 10);
  await prisma.user.upsert({
    where: { username: 'admin' },
    create: {
      username: 'admin',
      userType: 'ADMIN',
      auth: { create: { passwordHash: hash } },
      adminRole: { create: { roleId: superAdminRole.id } },
    },
    update: {},
  });
}

async function seedStaffDemoUser(
  username: string,
  password: string,
  roleId: bigint,
) {
  const hash = await bcrypt.hash(password, 10);
  const user = await prisma.user.upsert({
    where: { username },
    create: {
      username,
      userType: 'ADMIN',
      auth: { create: { passwordHash: hash } },
      adminRole: { create: { roleId } },
    },
    update: {
      userType: 'ADMIN',
      status: 'ACTIVE',
    },
  });
  await prisma.userAuth.upsert({
    where: { userId: user.id },
    create: { userId: user.id, passwordHash: hash },
    update: {
      passwordHash: hash,
      loginFailCount: 0,
      lockedUntil: null,
    },
  });
  await prisma.adminUserRole.upsert({
    where: { userId: user.id },
    create: { userId: user.id, roleId },
    update: { roleId },
  });
}

async function seedDevStaffUsers(roles: {
  matchAdminRole: { id: bigint };
  financeAdminRole: { id: bigint };
  supportRole: { id: bigint };
}) {
  await seedStaffDemoUser('matchadmin', 'MatchAdmin@123', roles.matchAdminRole.id);
  await seedStaffDemoUser('financeadmin', 'FinanceAdmin@123', roles.financeAdminRole.id);
  await seedStaffDemoUser('support1', 'Support@123', roles.supportRole.id);
}

async function seedDevDemoUsers() {
  const agentHash = await bcrypt.hash('Agent@123', 10);
  const playerHash = await bcrypt.hash('Player@123', 10);

  const agent1 = await prisma.user.upsert({
    where: { username: 'agent1' },
    create: {
      username: 'agent1',
      userType: 'AGENT',
      agentLevel: 1,
      auth: { create: { passwordHash: agentHash } },
      agentProfile: { create: { level: 1, creditLimit: 100000 } },
    },
    update: {},
  });

  await prisma.agentClosure.upsert({
    where: { ancestorId_descendantId: { ancestorId: agent1.id, descendantId: agent1.id } },
    create: { ancestorId: agent1.id, descendantId: agent1.id, depth: 0 },
    update: {},
  });

  await prisma.user.upsert({
    where: { username: 'agent2' },
    create: {
      username: 'agent2',
      userType: 'AGENT',
      agentLevel: 2,
      parentId: agent1.id,
      auth: { create: { passwordHash: agentHash } },
      agentProfile: { create: { level: 2, parentAgentId: agent1.id, creditLimit: 30000 } },
    },
    update: {},
  });

  const agent2 = await prisma.user.findUnique({ where: { username: 'agent2' }, select: { id: true } });
  if (agent2) {
    await prisma.agentClosure.upsert({
      where: { ancestorId_descendantId: { ancestorId: agent2.id, descendantId: agent2.id } },
      create: { ancestorId: agent2.id, descendantId: agent2.id, depth: 0 },
      update: {},
    });
    await prisma.agentClosure.upsert({
      where: { ancestorId_descendantId: { ancestorId: agent1.id, descendantId: agent2.id } },
      create: { ancestorId: agent1.id, descendantId: agent2.id, depth: 1 },
      update: {},
    });
  }

  await prisma.user.upsert({
    where: { username: 'player1' },
    create: {
      username: 'player1',
      userType: 'PLAYER',
      parentId: agent1.id,
      auth: { create: { passwordHash: playerHash } },
      wallet: { create: { availableBalance: 1000 } },
      preferences: { create: { locale: 'zh-CN', managedPassword: 'Player@123' } },
    },
    update: {},
  });
}

async function seedPlayerDemo() {
  const player = await prisma.user.findUnique({
    where: { username: 'player1' },
    include: { wallet: true },
  });
  if (!player?.wallet) return;

  await prisma.wallet.update({
    where: { id: player.wallet.id },
    data: { availableBalance: 88888.88 },
  });

  await prisma.walletTransaction.upsert({
    where: { transactionId: 'DEMO-DEP-001' },
    create: {
      transactionId: 'DEMO-DEP-001',
      userId: player.id,
      walletId: player.wallet.id,
      transactionType: 'DEPOSIT',
      amount: 50000,
      balanceBefore: 1000,
      balanceAfter: 51000,
      frozenBefore: 0,
      frozenAfter: 0,
      remark: '演示充值',
    },
    update: {},
  });

  await prisma.walletTransaction.upsert({
    where: { transactionId: 'DEMO-DEP-002' },
    create: {
      transactionId: 'DEMO-DEP-002',
      userId: player.id,
      walletId: player.wallet.id,
      transactionType: 'DEPOSIT',
      amount: 37888.88,
      balanceBefore: 51000,
      balanceAfter: 88888.88,
      frozenBefore: 0,
      frozenAfter: 0,
      remark: '演示充值（二笔）',
    },
    update: {},
  });

  const legacyDemoBets = await prisma.bet.findMany({
    where: { betNo: { in: ['DEMO-BET-001', 'DEMO-BET-002'] } },
    select: { id: true },
  });
  if (legacyDemoBets.length > 0) {
    const betIds = legacyDemoBets.map((b) => b.id);
    await prisma.settlementItem.deleteMany({ where: { betId: { in: betIds } } });
    await prisma.cashbackBet.deleteMany({ where: { betId: { in: betIds } } });
    await prisma.betSelection.deleteMany({ where: { betId: { in: betIds } } });
    await prisma.bet.deleteMany({ where: { id: { in: betIds } } });
  }

  console.log('  Player demo: wallet + transactions (no catalog demo bets)');
}

async function seedI18nMessages() {
  const messages = [
    { key: 'nav.home', zh: '首页', ms: 'Laman Utama', en: 'Home' },
    { key: 'nav.football', zh: '足球', ms: 'Bola Sepak', en: 'Football' },
    { key: 'bet.place_bet', zh: '确认下注', ms: 'Letak Pertaruhan', en: 'Place Bet' },
    { key: 'error.insufficient_balance', zh: '余额不足', ms: 'Baki tidak mencukupi', en: 'Insufficient balance' },
  ];

  for (const m of messages) {
    for (const [locale, value] of [['zh-CN', m.zh], ['ms-MY', m.ms], ['en-US', m.en]] as const) {
      await prisma.i18nMessage.upsert({
        where: { msgKey_locale: { msgKey: m.key, locale } },
        create: { msgKey: m.key, locale, value },
        update: { value },
      });
    }
  }
}

async function seedDefaultSiteContent() {
  await prisma.content.create({
    data: {
      contentType: 'BANNER',
      status: 'ACTIVE',
      sortOrder: 1,
      linkType: 'ROUTE',
      linkTarget: '/football',
      translations: {
        create: [
          { locale: 'zh-CN', title: '欢迎投注', body: '足球赛事火热进行中', imageUrl: '/uploads/banners/welcome.svg' },
          { locale: 'en-US', title: 'Welcome', body: 'Football matches available', imageUrl: '/uploads/banners/welcome.svg' },
        ],
      },
    },
  }).catch(() => {});

  await prisma.content.create({
    data: {
      contentType: 'BANNER',
      status: 'ACTIVE',
      sortOrder: 2,
      translations: {
        create: [
          { locale: 'zh-CN', title: '首存礼遇', body: '新会员专属优惠', imageUrl: '/uploads/banners/promo.svg' },
          { locale: 'en-US', title: 'First Deposit', body: 'New member offer', imageUrl: '/uploads/banners/promo.svg' },
        ],
      },
    },
  }).catch(() => {});

  await prisma.content.create({
    data: {
      contentType: 'BANNER',
      status: 'ACTIVE',
      sortOrder: 3,
      linkType: 'ROUTE',
      linkTarget: '/football',
      translations: {
        create: [
          { locale: 'zh-CN', title: '热门赛事', body: '五大联赛天天有球', imageUrl: '/uploads/banners/hot-matches.svg' },
          { locale: 'en-US', title: 'Hot Matches', body: 'Top leagues daily', imageUrl: '/uploads/banners/hot-matches.svg' },
        ],
      },
    },
  }).catch(() => {});

  await prisma.content.create({
    data: {
      contentType: 'TICKER',
      status: 'ACTIVE',
      sortOrder: 1,
      translations: {
        create: [
          { locale: 'zh-CN', body: '欢迎来到 TheBet365 · 热门赛事每日更新 · 请理性投注' },
          { locale: 'en-US', body: 'Welcome to TheBet365 · Daily hot matches · Bet responsibly' },
        ],
      },
    },
  }).catch(() => {});

  await prisma.content.create({
    data: {
      contentType: 'NOTICE',
      status: 'ACTIVE',
      sortOrder: 1,
      translations: {
        create: [
          { locale: 'zh-CN', title: '系统维护通知：每周一 04:00-05:00 例行维护，敬请谅解' },
          { locale: 'en-US', title: 'Maintenance: Every Mon 04:00-05:00 UTC' },
        ],
      },
    },
  }).catch(() => {});
}

async function ensureStaffInviteCodes() {
  const staffWithoutInvite = await prisma.user.findMany({
    where: { userType: { in: ['ADMIN', 'AGENT'] }, inviteCode: null },
    select: { id: true },
  });
  for (const row of staffWithoutInvite) {
    await ensureUserInviteCode(prisma, row.id);
  }
}

export async function runSeed(client: PrismaClient, options?: RunSeedOptions) {
  prisma = client;
  const mode = resolveSeedMode(options);
  console.log(`Seeding database (mode=${mode})...`);

  const roles = await seedRolesAndConfig();
  await seedAdminUser(roles.superAdminRole);

  if (mode === 'dev') {
    await seedDevStaffUsers(roles);
    await seedDevDemoUsers();
  }

  await seedI18nMessages();
  await seedCatalog(prisma);

  if (mode === 'dev') {
    await seedPlayerDemo();
  }

  await seedDefaultSiteContent();
  await ensureStaffInviteCodes();

  const accounts = resolveSeedAccounts(mode);
  console.log(`Seed completed! ${accounts.join(', ')}`);
}
