import * as core from "@actions/core";
import {
  BitwardenClient,
  ClientSettings,
  DeviceType,
  LogLevel,
} from "@bitwarden/sdk-napi";
import { parseSecretInput, SecretInput } from "./parser";

interface Inputs {
  clientId: string;
  clientSecret: string;
  password: string;
  server: string;
  secrets: string[];
}

export async function run(): Promise<void> {
  try {
    const inputs = readInputs();

    core.info("🔑 Logging into Bitwarden...");
    const client = await getBitwardenClient(inputs);

    const secretInputs = parseSecretInput(inputs.secrets);

    core.info("🔍 Retrieving secrets...");
    await retrieveAndSetSecrets(client, secretInputs);

    core.info("✅ Successfully retrieved and set secrets!");
  } catch (error) {
    core.setFailed(
      `❌ Error: ${error instanceof Error ? error.message : error}`
    );
  }
}

function readInputs(): Inputs {
  const clientId = core.getInput("client-id", { required: true });
  const clientSecret = core.getInput("client-secret", { required: true });
  const password = core.getInput("password", { required: true });
  const server = core.getInput("server", { required: true }); // Je eigen Bitwarden server
  const secretsRaw = core.getInput("secrets", { required: true });

  const secrets = secretsRaw
    .split("\n")
    .map((s) => s.trim())
    .filter((s) => s.includes(">"));

  if (secrets.length === 0) {
    throw new Error("No valid secrets provided.");
  }

  return { clientId, clientSecret, password, server, secrets };
}

async function retrieveAndSetSecrets(
  client: BitwardenClient,
  secretsInput: SecretInput[]
) {
  const secretIds = secretsInput.map((secret) => secret.id);

  const secretResponse = await client.secrets().getByIds(secretIds);

  if (secretResponse.success && secretResponse.data) {
    const fetchedSecrets = secretResponse.data.data;

    fetchedSecrets.forEach((secret) => {
      const secretInput = secretsInput.find((input) => input.id === secret.id);

      if (secretInput) {
        core.setSecret(secret.value);
        core.exportVariable(secretInput.outputEnvName, secret.value);
        core.setOutput(secretInput.outputEnvName, secret.value);
      }
    });
  } else {
    throw new Error(
      `The secrets provided could not be found. Please check the machine account has access to the secret UUIDs provided.\nError: ${secretResponse.errorMessage}`
    );
  }

  core.info("✅ Completed setting secrets as environment variables.");
}

async function getBitwardenClient(inputs: Inputs): Promise<BitwardenClient> {
  const settings: ClientSettings = {
    identityUrl: `${inputs.server}/identity`,
    apiUrl: `${inputs.server}/api`,
    userAgent: "actions/warden",
    deviceType: DeviceType.SDK,
  };

  const client = new BitwardenClient(settings, LogLevel.Info);
  const result = await client.loginWithAccessToken(inputs.clientSecret);
  if (!result.success) {
    throw Error(
      `Authentication with Bitwarden failed.\nError: ${result.errorMessage}`
    );
  }

  return client;
}
