/*!
 * SPDX-License-Identifier: Unlicense
 * This file was automatically generated by https://github.com/yt-dlp/ejs
 */
var jsc = (function (meriyah, astring) {
  'use strict';
  function matchesStructure(obj, structure) {
    if (Array.isArray(structure)) {
      if (!Array.isArray(obj)) {
        return false;
      }
      return (
        structure.length === obj.length &&
        structure.every((value, index) => matchesStructure(obj[index], value))
      );
    }
    if (typeof structure === 'object') {
      if (!obj) {
        return !structure;
      }
      if ('or' in structure) {
        return structure.or.some((node) => matchesStructure(obj, node));
      }
      if ('anykey' in structure && Array.isArray(structure.anykey)) {
        const haystack = Array.isArray(obj) ? obj : Object.values(obj);
        return structure.anykey.every((value) =>
          haystack.some((el) => matchesStructure(el, value)),
        );
      }
      for (const [key, value] of Object.entries(structure)) {
        if (!matchesStructure(obj[key], value)) {
          return false;
        }
      }
      return true;
    }
    return structure === obj;
  }
  function isOneOf(value, ...of) {
    return of.includes(value);
  }
  function generateArrowFunction(data) {
    return meriyah.parse(data).body[0].expression;
  }
  function _optionalChain$1(ops) {
    let lastAccessLHS = undefined;
    let value = ops[0];
    let i = 1;
    while (i < ops.length) {
      const op = ops[i];
      const fn = ops[i + 1];
      i += 2;
      if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) {
        return undefined;
      }
      if (op === 'access' || op === 'optionalAccess') {
        lastAccessLHS = value;
        value = fn(value);
      } else if (op === 'call' || op === 'optionalCall') {
        value = fn((...args) => value.call(lastAccessLHS, ...args));
        lastAccessLHS = undefined;
      }
    }
    return value;
  }
  const identifier = {
    or: [
      {
        type: 'ExpressionStatement',
        expression: {
          type: 'AssignmentExpression',
          operator: '=',
          left: { or: [{ type: 'Identifier' }, { type: 'MemberExpression' }] },
          right: { type: 'FunctionExpression', async: false },
        },
      },
      { type: 'FunctionDeclaration', async: false, id: { type: 'Identifier' } },
      {
        type: 'VariableDeclaration',
        declarations: {
          anykey: [
            {
              type: 'VariableDeclarator',
              init: { type: 'FunctionExpression', async: false },
            },
          ],
        },
      },
    ],
  };
  const asdasd = {
    type: 'ExpressionStatement',
    expression: {
      type: 'CallExpression',
      callee: {
        type: 'MemberExpression',
        object: { type: 'Identifier' },
        property: {},
        optional: false,
      },
      arguments: [
        { type: 'Literal', value: 'alr' },
        { type: 'Literal', value: 'yes' },
      ],
      optional: false,
    },
  };
  function extract(node) {
    if (!matchesStructure(node, identifier)) {
      return null;
    }
    const options = [];
    if (node.type === 'FunctionDeclaration') {
      if (
        node.id &&
        _optionalChain$1([
          node,
          'access',
          (_) => _.body,
          'optionalAccess',
          (_2) => _2.body,
        ])
      ) {
        options.push({
          name: node.id,
          statements: _optionalChain$1([
            node,
            'access',
            (_3) => _3.body,
            'optionalAccess',
            (_4) => _4.body,
          ]),
        });
      }
    } else if (node.type === 'ExpressionStatement') {
      if (node.expression.type !== 'AssignmentExpression') {
        return null;
      }
      const name = node.expression.left;
      const body = _optionalChain$1([
        node.expression.right,
        'optionalAccess',
        (_5) => _5.body,
        'optionalAccess',
        (_6) => _6.body,
      ]);
      if (name && body) {
        options.push({ name: name, statements: body });
      }
    } else if (node.type === 'VariableDeclaration') {
      for (const declaration of node.declarations) {
        const name = declaration.id;
        const body = _optionalChain$1([
          declaration.init,
          'optionalAccess',
          (_7) => _7.body,
          'optionalAccess',
          (_8) => _8.body,
        ]);
        if (name && body) {
          options.push({ name: name, statements: body });
        }
      }
    }
    for (const { name: name, statements: statements } of options) {
      if (matchesStructure(statements, { anykey: [asdasd] })) {
        return createSolver(name);
      }
    }
    return null;
  }
  function createSolver(expression) {
    return generateArrowFunction(
      `\n({sig, n}) => {\n  const url = (${astring.generate(expression)})("https://youtube.com/watch?v=yt-dlp-wins", "s", sig ? encodeURIComponent(sig) : undefined);\n  url.set("n", n);\n  const proto = Object.getPrototypeOf(url);\n  const keys = Object.keys(proto).concat(Object.getOwnPropertyNames(proto));\n  for (const key of keys) {\n    if (!["constructor", "set", "get", "clone"].includes(key)) {\n      url[key]();\n      break;\n    }\n  }\n  const s = url.get("s");\n  return {\n    sig: s ? decodeURIComponent(s) : null,\n    n: url.get("n") ?? null,\n  };\n}\n`,
    );
  }
  const setupNodes = meriyah.parse(
    `\nif (typeof globalThis.XMLHttpRequest === "undefined") {\n    globalThis.XMLHttpRequest = { prototype: {} };\n}\nif (typeof URL === "undefined") {\n    globalThis.location = {\n        hash: "",\n        host: "www.youtube.com",\n        hostname: "www.youtube.com",\n        href: "https://www.youtube.com/watch?v=yt-dlp-wins",\n        origin: "https://www.youtube.com",\n        password: "",\n        pathname: "/watch",\n        port: "",\n        protocol: "https:",\n        search: "?v=yt-dlp-wins",\n        username: "",\n    };\n} else {\n    globalThis.location = new URL("https://www.youtube.com/watch?v=yt-dlp-wins");\n}\nif (typeof globalThis.document === "undefined") {\n    globalThis.document = Object.create(null);\n}\nif (typeof globalThis.navigator === "undefined") {\n    globalThis.navigator = Object.create(null);\n}\nif (typeof globalThis.self === "undefined") {\n    globalThis.self = globalThis;\n}\nif (typeof globalThis.window === "undefined") {\n    globalThis.window = globalThis;\n}\n`,
  ).body;
  function _optionalChain(ops) {
    let lastAccessLHS = undefined;
    let value = ops[0];
    let i = 1;
    while (i < ops.length) {
      const op = ops[i];
      const fn = ops[i + 1];
      i += 2;
      if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) {
        return undefined;
      }
      if (op === 'access' || op === 'optionalAccess') {
        lastAccessLHS = value;
        value = fn(value);
      } else if (op === 'call' || op === 'optionalCall') {
        value = fn((...args) => value.call(lastAccessLHS, ...args));
        lastAccessLHS = undefined;
      }
    }
    return value;
  }
  function preprocessPlayer(data) {
    const program = meriyah.parse(data);
    const plainStatements = modifyPlayer(program);
    const solutions = getSolutions(plainStatements);
    for (const [name, options] of Object.entries(solutions)) {
      plainStatements.push({
        type: 'ExpressionStatement',
        expression: {
          type: 'AssignmentExpression',
          operator: '=',
          left: {
            type: 'MemberExpression',
            computed: false,
            object: { type: 'Identifier', name: '_result' },
            property: { type: 'Identifier', name: name },
            optional: false,
          },
          right: multiTry(options),
        },
      });
    }
    program.body.splice(0, 0, ...setupNodes);
    return astring.generate(program);
  }
  function modifyPlayer(program) {
    const body = program.body;
    const block = (() => {
      switch (body.length) {
        case 1: {
          const func = body[0];
          if (
            _optionalChain([func, 'optionalAccess', (_) => _.type]) ===
              'ExpressionStatement' &&
            func.expression.type === 'CallExpression' &&
            func.expression.callee.type === 'MemberExpression' &&
            func.expression.callee.object.type === 'FunctionExpression'
          ) {
            return func.expression.callee.object.body;
          }
          break;
        }
        case 2: {
          const func = body[1];
          if (
            _optionalChain([func, 'optionalAccess', (_2) => _2.type]) ===
              'ExpressionStatement' &&
            func.expression.type === 'CallExpression' &&
            func.expression.callee.type === 'FunctionExpression'
          ) {
            const block = func.expression.callee.body;
            block.body.splice(0, 1);
            return block;
          }
          break;
        }
      }
      throw 'unexpected structure';
    })();
    block.body = block.body.filter((node) => {
      if (node.type === 'ExpressionStatement') {
        if (node.expression.type === 'AssignmentExpression') {
          return true;
        }
        return node.expression.type === 'Literal';
      }
      return true;
    });
    return block.body;
  }
  function getSolutions(statements) {
    const found = { n: [], sig: [] };
    for (const statement of statements) {
      const result = extract(statement);
      if (result) {
        found.n.push(makeSolver(result, { type: 'Identifier', name: 'n' }));
        found.sig.push(makeSolver(result, { type: 'Identifier', name: 'sig' }));
      }
    }
    return found;
  }
  function makeSolver(result, ident) {
    return {
      type: 'ArrowFunctionExpression',
      params: [ident],
      body: {
        type: 'MemberExpression',
        object: {
          type: 'CallExpression',
          callee: result,
          arguments: [
            {
              type: 'ObjectExpression',
              properties: [
                {
                  type: 'Property',
                  key: ident,
                  value: ident,
                  kind: 'init',
                  computed: false,
                  method: false,
                  shorthand: true,
                },
              ],
            },
          ],
          optional: false,
        },
        computed: false,
        property: ident,
        optional: false,
      },
      async: false,
      expression: true,
      generator: false,
    };
  }
  function getFromPrepared(code) {
    const resultObj = { n: null, sig: null };
    Function('_result', code)(resultObj);
    return resultObj;
  }
  function multiTry(generators) {
    return generateArrowFunction(
      `\n(_input) => {\n  const _results = new Set();\n  const errors = [];\n  for (const _generator of ${astring.generate({ type: 'ArrayExpression', elements: generators })}) {\n    try {\n      _results.add(_generator(_input));\n    } catch (e) {\n      errors.push(e);\n    }\n  }\n  if (!_results.size) {\n    throw \`no solutions: \${errors.join(", ")}\`;\n  }\n  if (_results.size !== 1) {\n    throw \`invalid solutions: \${[..._results].map(x => JSON.stringify(x)).join(", ")}\`;\n  }\n  return _results.values().next().value;\n}\n`,
    );
  }
  function main(input) {
    const preprocessedPlayer =
      input.type === 'player'
        ? preprocessPlayer(input.player)
        : input.preprocessed_player;
    const solvers = getFromPrepared(preprocessedPlayer);
    const responses = input.requests.map((input) => {
      if (!isOneOf(input.type, 'n', 'sig')) {
        return { type: 'error', error: `Unknown request type: ${input.type}` };
      }
      const solver = solvers[input.type];
      if (!solver) {
        return {
          type: 'error',
          error: `Failed to extract ${input.type} function`,
        };
      }
      try {
        return {
          type: 'result',
          data: Object.fromEntries(
            input.challenges.map((challenge) => [challenge, solver(challenge)]),
          ),
        };
      } catch (error) {
        return {
          type: 'error',
          error:
            error instanceof Error
              ? `${error.message}\n${error.stack}`
              : `${error}`,
        };
      }
    });
    const output = { type: 'result', responses: responses };
    if (input.type === 'player' && input.output_preprocessed) {
      output.preprocessed_player = preprocessedPlayer;
    }
    return output;
  }
  return main;
})(meriyah, astring);
