import type { OneboxDatabase } from '../ts/database/index.js';
import { logger } from '../ts/logging.js';

const legacyType = 'smartproxy';
const legacyContainerName = 'onebox-smartproxy';
const legacyAdminTokenKey = 'smartproxyAdminToken';
const coreTrafficType = 'coretraffic';
const coreTrafficContainerName = 'onebox-coretraffic';
const coreTrafficAdminTokenKey = 'coretrafficAdminToken';

interface IKeyedDoc {
  key: string;
  save(): Promise<void>;
  delete(): Promise<void>;
}

const renameKeyedDoc = async (
  getDocArg: (keyArg: string) => Promise<IKeyedDoc | null>,
  legacyKeyArg: string,
  canonicalKeyArg: string,
): Promise<void> => {
  const legacyDoc = await getDocArg(legacyKeyArg);
  if (!legacyDoc) return;

  const canonicalDoc = await getDocArg(canonicalKeyArg);
  if (canonicalDoc) {
    await legacyDoc.delete();
    return;
  }

  legacyDoc.key = canonicalKeyArg;
  await legacyDoc.save();
};

const renameAdminTokenSetting = async (databaseArg: OneboxDatabase): Promise<void> => {
  await renameKeyedDoc(
    async (keyArg) => await databaseArg.CSecretSetting.getInstance({ key: keyArg }),
    legacyAdminTokenKey,
    coreTrafficAdminTokenKey,
  );
  await renameKeyedDoc(
    async (keyArg) => await databaseArg.CSetting.getInstance({ key: keyArg }),
    legacyAdminTokenKey,
    coreTrafficAdminTokenKey,
  );
};

export const runCoreTrafficPlatformRenameMigration = async (
  databaseArg: OneboxDatabase,
): Promise<void> => {
  await renameAdminTokenSetting(databaseArg);

  if ((await databaseArg.getSetting('dcrouterTargetHost')) === legacyContainerName) {
    await databaseArg.setSetting('dcrouterTargetHost', coreTrafficContainerName);
  }

  const services = await databaseArg.CService.getInstances({});
  for (const service of services) {
    const requirements = service.platformRequirements as Record<string, boolean> | undefined;
    if (!requirements?.[legacyType]) continue;
    service.platformRequirements = {
      ...requirements,
      [coreTrafficType]: requirements[legacyType],
      [legacyType]: undefined,
    } as typeof service.platformRequirements;
    delete (service.platformRequirements as Record<string, boolean | undefined>)[legacyType];
    service.updatedAt = Date.now();
    await service.save();
  }

  const platformServices = await databaseArg.CPlatformService.getInstances({});
  let coreTrafficPlatformService = platformServices.find((platformServiceArg) => {
    return (platformServiceArg.type as string) === coreTrafficType;
  });
  const legacyPlatformServices = platformServices.filter((platformServiceArg) => {
    return (platformServiceArg.type as string) === legacyType;
  });

  for (const platformService of legacyPlatformServices) {
    if (coreTrafficPlatformService && coreTrafficPlatformService.id !== platformService.id) {
      if (platformService.id) {
        await databaseArg.deletePlatformService(platformService.id);
      }
      continue;
    }

    platformService.type = coreTrafficType as typeof platformService.type;
    platformService.name = platformService.name === legacyContainerName
      ? coreTrafficContainerName
      : platformService.name.replaceAll(legacyType, coreTrafficType);
    platformService.containerId = platformService.containerId === legacyContainerName
      ? coreTrafficContainerName
      : platformService.containerId;
    platformService.status = 'stopped';
    platformService.config = {
      ...platformService.config,
      image: 'code.foss.global/serve.zone/coretraffic:latest',
    };
    platformService.updatedAt = Date.now();
    await platformService.save();
    coreTrafficPlatformService = platformService;
  }

  const backups = await databaseArg.CBackup.getInstances({});
  for (const backup of backups) {
    if (!backup.platformResources?.includes(legacyType as typeof backup.platformResources[number])) continue;
    backup.platformResources = backup.platformResources.map((platformResourceArg) => {
      return (platformResourceArg as string) === legacyType
        ? coreTrafficType as typeof platformResourceArg
        : platformResourceArg;
    });
    await backup.save();
  }

  if (legacyPlatformServices.length > 0) {
    logger.info(`Migrated ${legacyPlatformServices.length} legacy proxy platform service record(s) to CoreTraffic`);
  }
};
