import type {
  TranslationSeedItem,
  TranslationSeedModule,
  TranslationSeedModuleResult,
  TranslationSeedResult,
} from "./translation-seed.types";

type TranslationRow = {
  id: number;
};

type TranslationSeedDatabase = {
  translation: {
    findUnique(args: {
      where: {
        module_page_translationKey: {
          module: string;
          page: string;
          translationKey: string;
        };
      };
      select?: {
        id: true;
      };
    }): Promise<TranslationRow | null>;

    create(args: {
      data: {
        module: string;
        page: string;
        translationKey: string;
        englishText: string;
        khmerText: string;
        parentId: number | null;
        isActive: boolean;
      };
      select?: {
        id: true;
      };
    }): Promise<TranslationRow>;
  };
};

function getDatabase(prisma: unknown): TranslationSeedDatabase {
  return prisma as TranslationSeedDatabase;
}

async function findTranslationId(
  db: TranslationSeedDatabase,
  module: string,
  page: string,
  translationKey: string,
): Promise<number | null> {
  const row = await db.translation.findUnique({
    where: {
      module_page_translationKey: {
        module,
        page,
        translationKey,
      },
    },
    select: {
      id: true,
    },
  });

  return row?.id ?? null;
}

async function resolveParentId(
  db: TranslationSeedDatabase,
  item: TranslationSeedItem,
): Promise<number | null> {
  if (!item.parent) {
    return null;
  }

  const parentId = await findTranslationId(
    db,
    item.parent.module,
    item.parent.page,
    item.parent.translationKey,
  );

  if (!parentId) {
    throw new Error(
      [
        "Translation seed parent was not found.",
        `Child: ${item.module}/${item.page}/${item.translationKey}`,
        `Parent: ${item.parent.module}/${item.parent.page}/${item.parent.translationKey}`,
      ].join(" "),
    );
  }

  return parentId;
}

/**
 * IMPORTANT:
 * This seed is intentionally CREATE-ONLY.
 *
 * Missing key -> CREATE.
 * Existing key -> KEEP database value.
 *
 * Therefore Admin edits in Translation Management are not overwritten
 * when seed runs again on Stage / Production.
 */
export async function seedTranslationItems(
  prisma: unknown,
  module: TranslationSeedModule,
  items: TranslationSeedItem[],
): Promise<TranslationSeedModuleResult> {
  const db = getDatabase(prisma);

  let created = 0;
  let kept = 0;

  for (const item of items) {
    const existingId = await findTranslationId(
      db,
      item.module,
      item.page,
      item.translationKey,
    );

    if (existingId) {
      kept += 1;
      continue;
    }

    const parentId = await resolveParentId(db, item);

    await db.translation.create({
      data: {
        module: item.module,
        page: item.page,
        translationKey: item.translationKey,
        englishText: item.englishText,
        khmerText: item.khmerText,
        parentId,
        isActive: item.isActive,
      },
      select: {
        id: true,
      },
    });

    created += 1;
  }

  return {
    module,
    total: items.length,
    created,
    kept,
  };
}

export function combineSeedResults(
  modules: TranslationSeedModuleResult[],
): TranslationSeedResult {
  return {
    total: modules.reduce((sum, item) => sum + item.total, 0),
    created: modules.reduce((sum, item) => sum + item.created, 0),
    kept: modules.reduce((sum, item) => sum + item.kept, 0),
    modules,
  };
}
