import {ActionReference, ActionMetadata, actionIdentifier} from "@github/actions-languageservice/action";
import {error} from "@github/actions-languageservice/log";
import {Octokit, RestEndpointMethodTypes} from "@octokit/rest";
import {parse} from "yaml";
import {TTLCache} from "./cache";

export async function fetchActionMetadata(
  client: Octokit,
  cache: TTLCache,
  action: ActionReference
): Promise<ActionMetadata | undefined> {
  const metadata = await cache.get(`${actionIdentifier(action)}/action-metadata`, undefined, () =>
    getActionMetadata(client, action)
  );
  if (!metadata) {
    return undefined;
  }

  // https://docs.github.com/actions/creating-actions/metadata-syntax-for-github-actions
  return parse(metadata);
}

async function getActionMetadata(client: Octokit, action: ActionReference): Promise<string | undefined> {
  let resp: RestEndpointMethodTypes["repos"]["getContent"]["response"];
  try {
    resp = await fetchAction(client, action);
  } catch (e: any) {
    error(`Failed to fetch action metadata for ${actionIdentifier(action)}: '${e?.message || "<no details>"}'`);
    return;
  }

  // https://docs.github.com/rest/repos/contents?apiVersion=2022-11-28
  // Ignore directories (array of files) and non-file content
  if (resp.data === undefined || Array.isArray(resp.data) || resp.data.type !== "file") {
    return undefined;
  }

  if (resp.data.content === undefined) {
    return undefined;
  }

  return Buffer.from(resp.data.content, "base64").toString("utf8");
}

async function fetchAction(client: Octokit, action: ActionReference) {
  try {
    return await client.repos.getContent({
      owner: action.owner,
      repo: action.name,
      ref: action.ref,
      path: action.path ? `${action.path}/action.yml` : "action.yml"
    });
  } catch (e: any) {
    // If action.yml doesn't exist, try action.yaml
    if (e.status === 404) {
      return await client.repos.getContent({
        owner: action.owner,
        repo: action.name,
        ref: action.ref,
        path: action.path ? `${action.path}/action.yaml` : "action.yaml"
      });
    } else {
      throw e;
    }
  }
}
