/**
 * @license
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import * as fs from 'fs';
import * as path from 'path';

import { Extractor, ExtractorConfig } from 'api-extractor-me';
import * as tmp from 'tmp';

import {
  pruneDts,
  removeUnusedImports
} from '../../../repo-scripts/prune-dts/prune-dts';

/* eslint-disable no-console */

// This script takes the output of the API Extractor, post-processes it using
// the pruned-dts script and then invokes API report to generate a report
// that only includes exported symbols. This is all done in temporary folders,
// all configuration is auto-generated for each run.

const baseApiExtractorConfigFile: string = path.resolve(
  __dirname,
  '../../../config/api-extractor.json'
);
const reportFolder = path.resolve(__dirname, '../../../common/api-review');
const tmpDir = tmp.dirSync().name;

function writeTypescriptConfig(): void {
  const tsConfigJson = {
    extends: path.resolve(__dirname, '../tsconfig.json'),
    include: [path.resolve(__dirname, '../src')],
    compilerOptions: {
      downlevelIteration: true  // Needed for FirebaseApp
    },
  };
  fs.writeFileSync(
    path.resolve(tmpDir, 'tsconfig.json'),
    JSON.stringify(tsConfigJson),
    { encoding: 'utf-8' }
  );
}

function writePackageJson(sdkVariant: 'exp' | 'lite'): void {
  const packageJson = {
    'name': `@firebase/firestore-${sdkVariant}`
  };
  const packageJsonPath = path.resolve(tmpDir, 'package.json');
  fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson), {
    encoding: 'utf-8'
  });
}

function loadApiExtractorConfig(
  typescriptDtsPath: string,
  rollupDtsPath: string,
  untrimmedRollupDtsPath: string,
  dtsRollupEnabled: boolean,
  apiReportEnabled: boolean
): ExtractorConfig {
  const apiExtractorJsonPath = path.resolve(tmpDir, 'api-extractor.json');
  const apiExtractorJson = {
    extends: baseApiExtractorConfigFile,
    mainEntryPointFilePath: typescriptDtsPath,
    'dtsRollup': {
      'enabled': dtsRollupEnabled,
      publicTrimmedFilePath: rollupDtsPath,
      untrimmedFilePath: untrimmedRollupDtsPath
    },
    'tsdocMetadata': {
      'enabled': false
    },
    'apiReport': {
      'enabled': apiReportEnabled,
      reportFolder
    },
    'messages': {
      'extractorMessageReporting': {
        'ae-missing-release-tag': {
          'logLevel': 'none'
        },
        'ae-unresolved-link': {
          'logLevel': 'none'
        },
        'ae-forgotten-export': {
          'logLevel': apiReportEnabled ? 'error' : 'none'
        }
      },
      'tsdocMessageReporting': {
        'tsdoc-undefined-tag': {
          'logLevel': 'none'
        }
      }
    }
  };
  fs.writeFileSync(apiExtractorJsonPath, JSON.stringify(apiExtractorJson), {
    encoding: 'utf-8'
  });
  return ExtractorConfig.loadFileAndPrepare(apiExtractorJsonPath);
}

export async function generateApi(sdkVariant: 'exp' | 'lite'): Promise<void> {
  // The .d.ts file generated by the Typescript compiler as we transpile our
  // sources
  const typescriptDtsPath: string = path.resolve(
    __dirname,
    `../dist/firestore/${sdkVariant}/index.d.ts`
  );
  // A "bundled" version of our d.ts files that includes all public and private
  // types
  const rollupDtsPath: string = path.resolve(
    __dirname,
    `../dist/${sdkVariant}/private.d.ts`
  );
  
  // A "bundled" version of our d.ts files that includes all public and private
  // types, but also include exports marked as @internal
  // This file is used by @firebase/firestore-compat to use internal exports
  const untrimmedRollupDtsPath: string = path.resolve(
    __dirname,
    `../dist/${sdkVariant}/internal.d.ts`
  );

  // A customer-facing d.ts file that only include the public APIs
  const publicDtsPath: string = path.resolve(
    __dirname,
    `../dist/${sdkVariant}/index.d.ts`
  );

  console.log(
    `Running API Extractor configuration for firestore-${sdkVariant}...`
  );
  writeTypescriptConfig();
  writePackageJson(sdkVariant);

  let extractorConfig = loadApiExtractorConfig(
    typescriptDtsPath,
    rollupDtsPath,
    untrimmedRollupDtsPath,
    /* dtsRollupEnabled= */ true,
    /* apiReportEnabled= */ false
  );
  Extractor.invoke(extractorConfig, {
    localBuild: true
  });

  console.log('Generated rollup DTS');
  pruneDts(rollupDtsPath, publicDtsPath);
  console.log('Pruned DTS file');
  await removeUnusedImports(publicDtsPath);
  console.log('Removed unused imports');

  extractorConfig = loadApiExtractorConfig(
    publicDtsPath,
    rollupDtsPath,
    untrimmedRollupDtsPath,
    /* dtsRollupEnabled= */ false,
    /* apiReportEnabled= */ true
  );
  Extractor.invoke(extractorConfig, { localBuild: true });
  console.log(
    `API report for firestore-${sdkVariant} written to ${reportFolder}`
  );
}

void generateApi('lite').then(() => generateApi('exp'));
