import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../database/prisma.service';

type ChampionAssetPayload =
  | {
      data?: Record<
        string,
        {
          id?: string;
          key?: string;
          name?: string;
          image?: { full?: string };
        }
      >;
    }
  | Record<
      string,
      {
        id?: string;
        key?: string;
        name?: string;
        image?: { full?: string };
      }
    >;

@Injectable()
export class ShareService {
  constructor(private readonly prisma: PrismaService) {}

  async getShare(shareKey: string) {
    const shareCard = await this.prisma.shareCard.findUnique({
      where: { shareKey },
      include: {
        snapshot: {
          include: {
            riotAccount: {
              include: {
                summoners: {
                  orderBy: { updatedAt: 'desc' },
                  take: 1,
                },
              },
            },
          },
        },
      },
    });
    if (!shareCard) throw new NotFoundException('Share card not found');

    await this.prisma.shareCard.update({
      where: { id: shareCard.id },
      data: { viewCount: { increment: 1 } },
    });

    const primaryChampionName = shareCard.snapshot.primaryChampionName;
    const championDisplayName = primaryChampionName
      ? await this.getChampionDisplayName(primaryChampionName)
      : null;
    const localizedTitle = `${formatGgtiTypeLabel(shareCard.snapshot.ggtiType)} 플레이어`;
    const localizedDescription = localizeChampionText(
      shareCard.description ?? shareCard.snapshot.aiSummary,
      primaryChampionName,
      championDisplayName,
    );
    const localizedSummary = localizeChampionText(
      shareCard.snapshot.aiSummary,
      primaryChampionName,
      championDisplayName,
    );
    const localizedDetail = localizeChampionText(
      shareCard.snapshot.aiDetail,
      primaryChampionName,
      championDisplayName,
    );

    return {
      shareKey: shareCard.shareKey,
      title: localizedTitle,
      description: localizedDescription,
      imageUrl: shareCard.imageUrl,
      viewCount: shareCard.viewCount.toString(),
      snapshot: {
        id: shareCard.snapshot.id,
        gameName: shareCard.snapshot.riotAccount.gameName,
        tagLine: shareCard.snapshot.riotAccount.tagLine,
        profileIconId: shareCard.snapshot.riotAccount.summoners[0]?.profileIconId ?? null,
        summonerLevel: shareCard.snapshot.riotAccount.summoners[0]?.summonerLevel ?? null,
        ggtiType: shareCard.snapshot.ggtiType,
        primaryChampionName,
        traitScores: shareCard.snapshot.traitScores,
        aiSummary: localizedSummary,
        aiDetail: localizedDetail,
      },
    };
  }

  private async getChampionDisplayName(championName: string) {
    const asset = await this.prisma.gameStaticAsset.findUnique({
      where: { assetKey: 'LOL_CHAMPIONS' },
      select: { payload: true },
    });
    const payload = (asset?.payload as ChampionAssetPayload | null) ?? {};
    const champions = 'data' in payload ? payload.data ?? {} : payload;
    const normalized = championName.toLowerCase();

    for (const champion of Object.values(champions)) {
      const variants = [
        champion.id?.toLowerCase(),
        champion.key?.toLowerCase(),
        champion.image?.full?.replace(/\.png$/i, '').toLowerCase(),
      ].filter((value): value is string => Boolean(value));

      if (variants.includes(normalized)) {
        return champion.name ?? championName;
      }
    }

    return championName;
  }
}

function localizeChampionText(
  text: string | null | undefined,
  championName: string | null,
  championDisplayName: string | null,
) {
  if (!text) return '';
  if (!championName || !championDisplayName || championName === championDisplayName) return text;

  const variants = new Set([championName, championName.toUpperCase(), championName.toLowerCase()]);
  let localized = text;

  variants.forEach((variant) => {
    localized = localized.replace(new RegExp(escapeRegExp(variant), 'g'), championDisplayName);
  });

  return localized;
}

function formatGgtiTypeLabel(value: string) {
  return value
    .split('-')
    .map((token) => {
      const key = token.trim().toUpperCase();
      const labels: Record<string, string> = {
        BAIT: '유도',
        CARRY: '캐리',
        FARM: '파밍',
        LIMIT: '리밋',
        ROAM: '로밍',
        SAFE: '안정',
        SHOT: '오더',
      };
      return labels[key] ?? key;
    })
    .join(' / ');
}

function escapeRegExp(value: string) {
  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
