import { sendAPIQuery } from '../../download/api/index.mjs';
import { apiCacheKey, getAPICache, clearAPICache } from '../../download/api/cache.mjs';
import { runConcurrentQueries } from '../../download/api/queue.mjs';
import '../../download/api/config.mjs';
import '../../download/api/fetch.mjs';
import 'fs';
import 'crypto';
import '../../misc/scan.mjs';

function identicalDates(actual, expected) {
  if (typeof actual !== "string") {
    return false;
  }
  if (actual === expected) {
    return true;
  }
  return new Date(actual).toString() === new Date(expected).toString();
}
async function figmaFilesQuery(options, cache) {
  if (!options.token) {
    throw new Error("Missing Figma API token");
  }
  const params = new URLSearchParams();
  if (options.ids) {
    params.set("ids", options.ids.join(","));
  }
  if (options.version) {
    params.set("version", options.version);
  }
  if (options.depth) {
    params.set("depth", options.depth.toString());
  }
  const queryParams = {
    uri: "https://api.figma.com/v1/files/" + options.file,
    params,
    headers: {
      "X-FIGMA-TOKEN": options.token
    }
  };
  const isModified = async () => {
    if (!cache || !options.ifModifiedSince) {
      return true;
    }
    const cacheKey = apiCacheKey(queryParams);
    const cachedData = await getAPICache(cache.dir, cacheKey);
    if (!cachedData) {
      return true;
    }
    let ifModifiedSince;
    if (options.ifModifiedSince === true) {
      try {
        const parsedData2 = JSON.parse(cachedData);
        if (typeof parsedData2.lastModified !== "string") {
          await clearAPICache(cache.dir);
          return true;
        }
        ifModifiedSince = parsedData2.lastModified;
      } catch (err) {
        await clearAPICache(cache.dir);
        return true;
      }
    } else {
      ifModifiedSince = options.ifModifiedSince;
    }
    const versionCheckParams = {
      ...queryParams,
      params: new URLSearchParams(params)
    };
    versionCheckParams.params.set("depth", "1");
    const data2 = await sendAPIQuery(versionCheckParams);
    try {
      if (typeof data2 === "string") {
        const parsedData2 = JSON.parse(data2);
        if (identicalDates(parsedData2.lastModified, ifModifiedSince)) {
          return false;
        }
      }
    } catch (err) {
    }
    await clearAPICache(cache.dir);
    return true;
  };
  if (!await isModified()) {
    return "not_modified";
  }
  const data = await sendAPIQuery(queryParams, cache);
  if (typeof data === "number") {
    throw new Error(`Error retrieving document from API: ${data}`);
  }
  let parsedData;
  try {
    parsedData = JSON.parse(data);
  } catch (err) {
    throw new Error(`Error retrieving document from API: invalid data`);
  }
  if (typeof parsedData.status === "number") {
    const figmaError = parsedData;
    throw new Error(
      `Error retrieving document from API: ${figmaError.err}`
    );
  }
  const document = parsedData;
  if (document.editorType !== "figma") {
    throw new Error(
      `Error retrieving document from API: document is for ${document.editorType}`
    );
  }
  if (identicalDates(options.ifModifiedSince, document.lastModified)) {
    return "not_modified";
  }
  return document;
}
async function figmaImagesQuery(options, nodes, cache) {
  const uri = "https://api.figma.com/v1/images/" + options.file;
  const maxLength = 2048 - uri.length;
  const svgOptions = options.svgOptions || {};
  const query = (ids2) => {
    return new Promise((resolve, reject) => {
      const params = new URLSearchParams({
        ids: ids2.join(","),
        format: "svg"
      });
      if (options.version) {
        params.set("version", options.version);
      }
      params.set(
        "svg_include_id",
        svgOptions.includeID ? "true" : "false"
      );
      params.set(
        "svg_simplify_stroke",
        svgOptions.simplifyStroke ? "true" : "false"
      );
      params.set(
        "use_absolute_bounds",
        svgOptions.useAbsoluteBounds ? "true" : "false"
      );
      sendAPIQuery(
        {
          uri,
          params,
          headers: {
            "X-FIGMA-TOKEN": options.token
          }
        },
        cache
      ).then((data) => {
        if (typeof data === "number") {
          reject(data);
          return;
        }
        let parsedData;
        try {
          parsedData = JSON.parse(data);
        } catch {
          reject("Bad API response");
          return;
        }
        resolve(parsedData);
      }).catch(reject);
    });
  };
  let ids = [];
  let idsLength = 0;
  const allKeys = Object.keys(nodes.icons);
  const queue = [];
  for (let i = 0; i < allKeys.length; i++) {
    const id = allKeys[i];
    ids.push(id);
    idsLength += id.length + 1;
    if (idsLength >= maxLength) {
      queue.push(ids.slice(0));
      ids = [];
      idsLength = 0;
    }
  }
  if (idsLength) {
    queue.push(ids.slice(0));
  }
  const queryParams = {
    // Params
    total: queue.length,
    callback: (index) => query(queue[index]),
    // Payload to identify failed items in onfail callback
    function: "figmaImagesQuery",
    payload: queue
  };
  const results = await runConcurrentQueries(queryParams);
  let found = 0;
  results.forEach((data) => {
    if (!data) {
      return;
    }
    const images = data.images;
    for (const id in images) {
      const node = nodes.icons[id];
      const target = images[id];
      if (node && target) {
        node.url = target;
        found++;
      }
    }
  });
  if (!found) {
    throw new Error("No valid icon layers were found");
  }
  nodes.generatedIconsCount = found;
  return nodes;
}
async function figmaDownloadImages(nodes, cache) {
  const icons = nodes.icons;
  const ids = Object.keys(icons);
  let count = 0;
  const filtered = [];
  for (let i = 0; i < ids.length; i++) {
    const id = ids[i];
    const item = icons[id];
    if (item.url) {
      filtered.push(item);
    }
  }
  const params = {
    // Params
    total: filtered.length,
    callback: (index) => {
      return new Promise((resolve, reject) => {
        const item = filtered[index];
        sendAPIQuery(
          {
            uri: item.url
          },
          cache
        ).then((data) => {
          if (typeof data === "string") {
            count++;
            item.content = data;
            resolve(void 0);
          } else {
            reject(data);
          }
        }).catch(reject);
      });
    },
    // Payload to identify failed items in onfail callback
    function: "figmaDownloadImages",
    payload: filtered
  };
  await runConcurrentQueries(params);
  if (!count) {
    throw new Error("Error retrieving images");
  }
  nodes.downloadedIconsCount = count;
  return nodes;
}

export { figmaDownloadImages, figmaFilesQuery, figmaImagesQuery };
