// @ts-check
const path = require('path');
const installPath = 'C:/Users/PowerSpec/AppData/Local/Plarium/PlariumPlay/StandAloneApps/raid/237';
const gameVersion = path.basename(installPath);

function getGameAssembly() {
  return Promise.resolve({
    dll: path.join(installPath, 'GameAssembly.dll'),
    metadata: path.join(installPath, 'Raid_Data/il2cpp_data/Metadata/global-metadata.dat'),
    version: gameVersion,
  });
}

const excludeEmptyTypes = {
  visitType: (type) => {
    var _a, _b, _c, _d;
    return (
      !!type.Type.BaseType ||
      !!((_a = type.NestedTypes) === null || _a === void 0 ? void 0 : _a.length) ||
      !!((_b = type.StaticFields) === null || _b === void 0 ? void 0 : _b.length) ||
      !!((_c = type.Fields) === null || _c === void 0 ? void 0 : _c.length) ||
      !!((_d = type.Type.Namespace) === null || _d === void 0 ? void 0 : _d.startsWith('System'))
    );
  },
  visitTypeUsage: () => true,
};

const includeRootTypes = {
  visitType: ({ Type }) => {
    if (Type.Namespace === 'Client.Model.Guard' && Type.TypeName === 'UserWrapper') {
      return excludeEmptyTypes;
    }
    if (Type.Namespace === 'Client.Model.Gameplay.Artifacts' && Type.TypeName === 'ExternalArtifactsStorage') {
      return excludeEmptyTypes;
    }
    if (
      Type.Namespace === 'SharedModel.Meta.Artifacts.ArtifactStorage' &&
      Type.TypeName === 'ArtifactStorageResolver'
    ) {
      return excludeEmptyTypes;
    }
    if (Type.Namespace === 'SharedModel.Meta' && Type.TypeName === 'ClientStaticData') {
      return excludeEmptyTypes;
    }
    if (Type.Namespace === 'Client.Model.Gameplay.StaticData' && Type.TypeName === 'ClientStaticDataManager') {
      return excludeEmptyTypes;
    }
    if (Type.Namespace === 'Client.App' && Type.TypeName === 'SingleInstance') {
      return excludeEmptyTypes;
    }
    if (Type.Namespace === 'Client.Model' && Type.TypeName === 'AppModel') {
      return excludeEmptyTypes;
    }
    if (Type.Namespace === 'Client.ViewModel' && Type.TypeName === 'AppViewModel') {
      return excludeEmptyTypes;
    }
    return false;
  },
  visitTypeUsage: () => false,
};

function isTypeAllowed(type) {
  if (!type.Namespace) {
    return false;
  }
  if (
    type.Namespace.startsWith('SharedModel') ||
    type.Namespace.startsWith('Client') ||
    type.Namespace.startsWith('Client.ViewModel')
  ) {
    if (type.Namespace?.startsWith('Client.Model.Network')) {
      return false;
    }
    return true;
  }
  return false;
}

module.exports = getGameAssembly().then((gameAssembly) => ({
  gameAssembly,
  filter: includeRootTypes,
  output: { entry: 'raid.ts', outputDir: 'src' },
  optimize: true,
  visitors: [
    {
      visitTypeDef(type) {
        if (type.TypeName === 'Fixed' && type.Type.Namespace === 'Plarium.Common.Numerics') {
          return undefined;
        }
        if (type.Type.TypeName === 'ArenaOpponent') {
          // No.
          return undefined;
        }
        if ((type.Type.DeclaringType && isTypeAllowed(type.Type.DeclaringType)) || isTypeAllowed(type.Type)) {
          return type;
        }
        return undefined;
      },
      visitField(field) {
        const result = /<(\w+)>k__BackingField/.exec(field.Name);
        if (result) {
          field.Name = result[1];
        }
        return field;
      },
      visitTypeUsage(ref) {
        if (ref.Namespace === 'System' && ref.TypeName === 'Action') {
          return undefined;
        }
        if (ref.TypeName === 'Fixed' && ref.Namespace === 'Plarium.Common.Numerics') {
          ref.TypeName = 'FixedNumber';
          ref.Indirection = 1;
          delete ref.Namespace;
        }
        return ref;
      },
    },
  ],
  rootNamespace: 'codegen',
  // @ts-ignore
  types: ['@il2js/core', { from: './FixedNumber', types: { FixedNumber: { boxedValue: 'number' } } }],
  targets: ['typescript'],
}));
