import type { PrismaClient } from '@prisma/client';
import { syncWc2026OutrightMarket } from '../../domains/catalog/wc2026-outright.sync';
import {
  WC2026_LEAGUE_CODE,
  WC2026_OUTRIGHT_TEAMS,
} from '../../domains/catalog/wc2026-outright-teams';
import type { ZhiboMatchExport, ZhiboTeamExport } from '../../domains/catalog/zhibo-match.types';
import {
  leagueCodeFromExport,
  resolveInternalStatus,
  resolveStartTime,
  teamCodeFromExport,
  toKickoffJson,
  toVenueJson,
  translationsFromZhiboNames,
} from '../../domains/catalog/zhibo-match.mapper';
import {
  WC2026_GROUP_STAGE_BUNDLE,
  WC2026_TEAM_LOGO_BY_CODE,
  WC2026_ZIBO_ID_TO_CODE,
} from './seed-data';
import { seedDemoMarkets } from './seed-demo-markets';

export { seedDemoMarkets };

/** 旧版演示联赛（已从 seed 移除，增量 seed 时软删其赛事） */
const LEGACY_DEMO_LEAGUE_CODES = ['EPL'] as const;

const CATALOG_PUBLISHABLE_STATUSES = ['DRAFT', 'PUBLISHED'] as const;

function getSeedLiveMatchIds(): bigint[] {
  return (WC2026_GROUP_STAGE_BUNDLE.matches ?? [])
    .filter((m) => m.liveMatchId != null)
    .map((m) => BigInt(m.liveMatchId!));
}

async function softDeleteLegacyDemoLeagueMatches(prisma: PrismaClient) {
  const leagues = await prisma.league.findMany({
    where: { code: { in: [...LEGACY_DEMO_LEAGUE_CODES] } },
    select: { id: true },
  });
  if (leagues.length === 0) return;

  const leagueIds = leagues.map((l) => l.id);
  await prisma.match.updateMany({
    where: { leagueId: { in: leagueIds }, deletedAt: null },
    data: { deletedAt: new Date() },
  });
  await prisma.league.updateMany({
    where: { id: { in: leagueIds } },
    data: { isActive: false },
  });
}

async function softDeleteStaleWc2026GroupMatches(prisma: PrismaClient, leagueId: bigint) {
  const seedIds = getSeedLiveMatchIds();
  await prisma.match.updateMany({
    where: {
      leagueId,
      isOutright: false,
      deletedAt: null,
      OR: [{ liveMatchId: null }, { liveMatchId: { notIn: seedIds } }],
    },
    data: { deletedAt: new Date() },
  });
}

async function purgeMatchCatalogBettingData(prisma: PrismaClient, matchIds: bigint[]) {
  if (matchIds.length === 0) return;

  const selections = await prisma.betSelection.findMany({
    where: { matchId: { in: matchIds } },
    select: { betId: true },
  });
  const betIds = [...new Set(selections.map((s) => s.betId))];

  if (betIds.length > 0) {
    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 } } });
  }

  await prisma.settlementBatch.deleteMany({ where: { matchId: { in: matchIds } } });
  await prisma.matchScore.deleteMany({ where: { matchId: { in: matchIds } } });
}

/** 增量 seed：清理 legacy 赛事、移除 WC2026 下注/结算/比分，保证仅保留 seed 包内小组赛 */
async function resetWc2026CatalogState(prisma: PrismaClient, leagueId: bigint) {
  await softDeleteLegacyDemoLeagueMatches(prisma);
  await softDeleteStaleWc2026GroupMatches(prisma, leagueId);

  const activeMatches = await prisma.match.findMany({
    where: { leagueId, deletedAt: null },
    select: { id: true },
  });
  await purgeMatchCatalogBettingData(
    prisma,
    activeMatches.map((m) => m.id),
  );
}

async function normalizeWc2026OutrightMatch(prisma: PrismaClient, leagueId: bigint) {
  const outright = await prisma.match.findFirst({
    where: { leagueId, isOutright: true, deletedAt: null },
  });
  if (!outright) return;

  if (!CATALOG_PUBLISHABLE_STATUSES.includes(outright.status as (typeof CATALOG_PUBLISHABLE_STATUSES)[number])) {
    await prisma.match.update({
      where: { id: outright.id },
      data: {
        status: 'PUBLISHED',
        publishTime: outright.publishTime ?? new Date(),
        closeTime: null,
      },
    });
  }
  await prisma.matchScore.deleteMany({ where: { matchId: outright.id } });
}

/** 清除 seed 后仍残留的已结算/已封盘等非发布态（小组赛 upsert 已写入 DRAFT/PUBLISHED） */
async function ensureWc2026PublishableStatuses(prisma: PrismaClient, leagueId: bigint) {
  await prisma.match.updateMany({
    where: {
      leagueId,
      deletedAt: null,
      status: { notIn: [...CATALOG_PUBLISHABLE_STATUSES] },
    },
    data: {
      status: 'PUBLISHED',
      closeTime: null,
      publishTime: new Date(),
    },
  });
}

async function upsertEntityTranslations(
  prisma: PrismaClient,
  entityType: 'LEAGUE' | 'TEAM',
  entityId: bigint,
  translations: Record<string, string>,
) {
  for (const [locale, value] of Object.entries(translations)) {
    await prisma.entityTranslation.upsert({
      where: {
        entityType_entityId_locale_fieldName: {
          entityType,
          entityId,
          locale,
          fieldName: 'name',
        },
      },
      create: { entityType, entityId, locale, fieldName: 'name', value },
      update: { value },
    });
  }
}

export async function seedWc2026League(prisma: PrismaClient) {
  const league = await prisma.league.upsert({
    where: { code: WC2026_LEAGUE_CODE },
    create: { code: WC2026_LEAGUE_CODE, sportType: 'FOOTBALL', isActive: true },
    update: { sportType: 'FOOTBALL', isActive: true },
  });
  await upsertEntityTranslations(prisma, 'LEAGUE', league.id, {
    'zh-CN': '2026世界杯(在加拿大,墨西哥和美国)',
    'en-US': '2026 FIFA World Cup',
  });
  return league;
}

export async function seedWc2026Teams(prisma: PrismaClient) {
  for (const entry of WC2026_OUTRIGHT_TEAMS) {
    const logoUrl = WC2026_TEAM_LOGO_BY_CODE[entry.code] ?? null;
    const externalIdEntry = Object.entries(WC2026_ZIBO_ID_TO_CODE).find(([, code]) => code === entry.code);
    const externalId = externalIdEntry ? Number(externalIdEntry[0]) : undefined;
    const team = await prisma.team.upsert({
      where: { code: entry.code },
      create: {
        code: entry.code,
        externalId,
        logoUrl,
      },
      update: {
        externalId: externalId ?? undefined,
        logoUrl: logoUrl ?? undefined,
      },
    });
    await upsertEntityTranslations(prisma, 'TEAM', team.id, entry.names);
  }
}

async function upsertWc2026TeamFromZhibo(prisma: PrismaClient, team: ZhiboTeamExport) {
  const canonicalCode =
    team.id != null ? WC2026_ZIBO_ID_TO_CODE[team.id] : undefined;
  const outrightEntry = canonicalCode
    ? WC2026_OUTRIGHT_TEAMS.find((t) => t.code === canonicalCode)
    : undefined;
  const code = canonicalCode ?? teamCodeFromExport(team);
  const zhiboTranslations = translationsFromZhiboNames(team.names, team.name);
  const translations = outrightEntry
    ? { ...outrightEntry.names, ...zhiboTranslations }
    : zhiboTranslations;
  const logoUrl =
    (canonicalCode && WC2026_TEAM_LOGO_BY_CODE[canonicalCode]) ||
    team.image ||
    undefined;

  const record = await prisma.team.upsert({
    where: { code },
    create: {
      code,
      externalId: team.id ?? undefined,
      logoUrl,
    },
    update: {
      externalId: team.id ?? undefined,
      logoUrl: logoUrl ?? undefined,
    },
  });
  await upsertEntityTranslations(prisma, 'TEAM', record.id, translations);
  return record;
}

async function findExistingZhiboMatch(
  prisma: PrismaClient,
  leagueId: bigint,
  homeTeamId: bigint,
  awayTeamId: bigint,
  item: ZhiboMatchExport,
) {
  if (item.liveMatchId != null) {
    return prisma.match.findUnique({
      where: { liveMatchId: BigInt(item.liveMatchId) },
    });
  }
  if (item.officialMatchNo != null) {
    return prisma.match.findFirst({
      where: {
        leagueId,
        homeTeamId,
        awayTeamId,
        officialMatchNo: item.officialMatchNo,
      },
    });
  }
  return null;
}

async function upsertWc2026GroupMatch(prisma: PrismaClient, item: ZhiboMatchExport, leagueId: bigint) {
  const [homeTeam, awayTeam] = await Promise.all([
    upsertWc2026TeamFromZhibo(prisma, item.homeTeam),
    upsertWc2026TeamFromZhibo(prisma, item.awayTeam),
  ]);

  const status = resolveInternalStatus(item);
  const startTime = resolveStartTime(item.kickoff);
  const liveMatchId = item.liveMatchId != null ? BigInt(item.liveMatchId) : undefined;
  const matchData = {
    leagueId,
    homeTeamId: homeTeam.id,
    awayTeamId: awayTeam.id,
    startTime,
    isHot: false,
    displayOrder: item.sortOrder,
    status,
    publishTime: status === 'PUBLISHED' ? new Date() : undefined,
    officialMatchNo: item.officialMatchNo,
    stage: item.stage,
    groupName: item.groupName,
    liveMatchId,
    additionMatchId: item.additionMatchId != null ? BigInt(item.additionMatchId) : null,
    channelId: item.channelId,
    matchName: item.matchName,
    venueJson: toVenueJson(item.venue),
    kickoffJson: toKickoffJson(item.kickoff),
    externalStatus: item.status.state,
  };

  const existing = await findExistingZhiboMatch(
    prisma,
    leagueId,
    homeTeam.id,
    awayTeam.id,
    item,
  );

  const match = existing
    ? await prisma.match.update({
        where: { id: existing.id },
        data: {
          ...matchData,
          deletedAt: null,
          closeTime: null,
          publishTime: status === 'PUBLISHED' ? (existing.publishTime ?? matchData.publishTime ?? new Date()) : null,
        },
      })
    : await prisma.match.create({ data: matchData });

  await prisma.matchScore.deleteMany({ where: { matchId: match.id } });
  await seedDemoMarkets(prisma, match.id);
  return match;
}

export async function seedWc2026GroupMatches(prisma: PrismaClient, leagueId: bigint) {
  const matches = WC2026_GROUP_STAGE_BUNDLE.matches ?? [];
  let created = 0;
  let updated = 0;

  for (const item of matches) {
    const code = leagueCodeFromExport(item.league);
    if (code !== WC2026_LEAGUE_CODE) {
      throw new Error(`Unexpected league in seed bundle: ${item.league.en}`);
    }
    const before = item.liveMatchId != null
      ? await prisma.match.findUnique({ where: { liveMatchId: BigInt(item.liveMatchId) } })
      : null;
    await upsertWc2026GroupMatch(prisma, item, leagueId);
    if (before) updated += 1;
    else created += 1;
  }

  return { total: matches.length, created, updated };
}

export async function seedWc2026Outright(prisma: PrismaClient) {
  const { matchId, marketId } = await syncWc2026OutrightMarket(prisma, {
    forceCanonical: true,
  });
  const count = await prisma.marketSelection.count({ where: { marketId } });
  return { matchId, marketId, selectionCount: count };
}

export async function seedCatalog(prisma: PrismaClient) {
  const league = await seedWc2026League(prisma);
  await seedWc2026Teams(prisma);
  await resetWc2026CatalogState(prisma, league.id);
  const groupResult = await seedWc2026GroupMatches(prisma, league.id);
  const outrightResult = await seedWc2026Outright(prisma);
  await normalizeWc2026OutrightMatch(prisma, league.id);
  await ensureWc2026PublishableStatuses(prisma, league.id);

  console.log(
    `  WC2026 catalog: ${groupResult.total} group matches (${groupResult.created} new, ${groupResult.updated} updated), outright ${outrightResult.selectionCount} selections`,
  );

  return { league, groupResult, outrightResult };
}
