text: "use strict";
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
      function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
      return new (P || (P = Promise))(function (resolve, reject) {
          function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
          function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
          function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
          step((generator = generator.apply(thisArg, _arguments || [])).next());
      });
  };
  Object.defineProperty(exports, "__esModule", { value: true });
  exports.debounce = exports.previewDocs = void 0;
  const colorette = require("colorette");
  const chockidar = require("chokidar");
  const openapi_core_1 = require("@redocly/openapi-core");
  const utils_1 = require("../../utils");
  const preview_server_1 = require("./preview-server/preview-server");
  function previewDocs(argv) {
      return __awaiter(this, void 0, void 0, function* () {
          let isAuthorizedWithRedocly = false;
          let redocOptions = {};
          let config = yield reloadConfig();
          const entrypoints = yield utils_1.getFallbackEntryPointsOrExit(argv.entrypoint ? [argv.entrypoint] : [], config);
          const entrypoint = entrypoints[0];
          let cachedBundle;
          const deps = new Set();
          function getBundle() {
              return __awaiter(this, void 0, void 0, function* () {
                  return cachedBundle;
              });
          }
          function updateBundle() {
              return __awaiter(this, void 0, void 0, function* () {
                  process.stdout.write('\nBundling...\n\n');
                  try {
                      const { bundle: openapiBundle, problems, fileDependencies } = yield openapi_core_1.bundle({
                          ref: entrypoint,
                          config,
                      });
                      const removed = [...deps].filter((x) => !fileDependencies.has(x));
                      watcher.unwatch(removed);
                      watcher.add([...fileDependencies]);
                      deps.clear();
                      fileDependencies.forEach(deps.add, deps);
                      const fileTotals = openapi_core_1.getTotals(problems);
                      if (fileTotals.errors === 0) {
                          process.stdout.write(fileTotals.errors === 0
                              ? `Created a bundle for ${entrypoint} ${fileTotals.warnings > 0 ? 'with warnings' : 'successfully'}\n`
                              : colorette.yellow(`Created a bundle for ${entrypoint} with errors. Docs may be broken or not accurate\n`));
                      }
                      return openapiBundle.parsed;
                  }
                  catch (e) {
                      handleError(e, entrypoint);
                  }
              });
          }
          setImmediate(() => {
              cachedBundle = updateBundle();
          }); // initial cache
          const isAuthorized = isAuthorizedWithRedocly || redocOptions.licenseKey;
          if (!isAuthorized) {
              process.stderr.write(`Using Redoc community edition.\nLogin with openapi-cli ${colorette.blue('login')} or use an enterprise license key to preview with the premium docs.\n\n`);
          }
          const hotClients = yield preview_server_1.default(argv.port, {
              getBundle,
              getOptions: () => redocOptions,
              useRedocPro: isAuthorized && !redocOptions.useCommunityEdition,
          });
          const watchPaths = [entrypoint, config.configFile].filter((e) => !!e);
          const watcher = chockidar.watch(watchPaths, {
              disableGlobbing: true,
              ignoreInitial: true,
          });
          const debouncedUpdatedBundle = debounce(() => __awaiter(this, void 0, void 0, function* () {
              cachedBundle = updateBundle();
              yield cachedBundle;
              hotClients.broadcast('{"type": "reload", "bundle": true}');
          }), 2000);
          const changeHandler = (type, file) => __awaiter(this, void 0, void 0, function* () {
              process.stdout.write(`${colorette.green('watch')} ${type} ${colorette.blue(file)}\n`);
              if (file === config.configFile) {
                  config = yield reloadConfig();
                  hotClients.broadcast(JSON.stringify({ type: 'reload' }));
                  return;
              }
              debouncedUpdatedBundle();
          });
          watcher.on('change', changeHandler.bind(undefined, 'changed'));
          watcher.on('add', changeHandler.bind(undefined, 'added'));
          watcher.on('unlink', changeHandler.bind(undefined, 'removed'));
          watcher.on('ready', () => {
              process.stdout.write(`\n  👀  Watching ${colorette.blue(entrypoint)} and all related resources for changes\n\n`);
          });
          function reloadConfig() {
              return __awaiter(this, void 0, void 0, function* () {
                  let config = yield openapi_core_1.loadConfig(argv.config);
                  config.lint.skipRules(argv['skip-rule']);
                  config.lint.skipPreprocessors(argv['skip-preprocessor']);
                  config.lint.skipDecorators(argv['skip-decorator']);
                  const redoclyClient = new openapi_core_1.RedoclyClient();
                  isAuthorizedWithRedocly = yield redoclyClient.isAuthorizedWithRedocly();
                  const referenceDocs = config.referenceDocs || {};
                  redocOptions = Object.assign(Object.assign({}, referenceDocs), { useCommunityEdition: argv['use-community-edition'] || referenceDocs.useCommunityEdition, licenseKey: process.env.REDOCLY_LICENSE_KEY || referenceDocs.licenseKey });
                  return config;
              });
          }
      });
  }
  exports.previewDocs = previewDocs;
  function debounce(func, wait, immediate) {
      let timeout;
      return function executedFunction(...args) {
          // @ts-ignore
          const context = this;
          const later = () => {
              timeout = null;
              if (!immediate)
                  func.apply(context, args);
          };
          const callNow = immediate && !timeout;
          if (timeout)
              clearTimeout(timeout);
          timeout = setTimeout(later, wait);
          if (callNow)
              func.apply(context, args);
      };
  }
  exports.debounce = debounce;
  function handleError(e, ref) {
      if (e instanceof openapi_core_1.ResolveError) {
          process.stderr.write(`Failed to resolve entrypoint definition at ${ref}:\n\n  - ${e.message}.\n\n`);
      }
      else if (e instanceof openapi_core_1.YamlParseError) {
          process.stderr.write(`Failed to parse entrypoint definition at ${ref}:\n\n  - ${e.message}.\n\n`);
      }
      else {
          process.stderr.write(`Something went wrong when processing ${ref}:\n\n  - ${e.message}.\n\n`);
      }
  }
  