import { AuthenticationClient, Scopes } from '@aps_sdk/authentication';
import { ModelDerivativeClient, View, OutputType } from '@aps_sdk/model-derivative';
import { OssClient, Region, PolicyKey } from '@aps_sdk/oss';

const apsClientId = 'PkqB8KlPGekLGKElPSjPhC9C2NGyXMN64QVhPSaqUhV46zEn';
const apsClientSecret = 'Jr70CpXFaV2PRd9lux3ZXBKpSMwFsyO6xq1Y7AJy1Q4xcK6nZMLq20KB8SlipC4Z';
const apsBucket = `${apsClientId.toLowerCase()}-basic-app`;
const authenticationClient = new AuthenticationClient();
const ossClient = new OssClient();
const modelDerivativeClient = new ModelDerivativeClient();

async function getInternalToken() {
  const credentials = await authenticationClient.getTwoLeggedToken(
    apsClientId,
    apsClientSecret,
    [Scopes.DataRead, Scopes.DataCreate, Scopes.DataWrite, Scopes.BucketCreate, Scopes.BucketRead],
  );
  return credentials.access_token;
}

export const getViewerToken = async () => {
  return await authenticationClient.getTwoLeggedToken(apsClientId, apsClientSecret, [
    Scopes.ViewablesRead,
  ]);
};

export const ensureBucketExists = async (bucketKey) => {
  const accessToken = await getInternalToken();
  try {
    await ossClient.getBucketDetails(bucketKey, { accessToken });
  } catch (err) {
    if (err.axiosError.response.status === 404) {
      await ossClient.createBucket(
        Region.Us,
        { bucketKey: bucketKey, policyKey: PolicyKey.Persistent },
        { accessToken },
      );
    } else {
      throw err;
    }
  }
};

export const listObjects = async () => {
  await ensureBucketExists(apsBucket);
  const accessToken = await getInternalToken();
  let resp = await ossClient.getObjects(apsBucket, { limit: 64, accessToken });
  let objects = resp.items;
  while (resp.next) {
    const startAt = new URL(resp.next).searchParams.get('startAt');
    resp = await ossClient.getObjects(apsBucket, { limit: 64, startAt, accessToken });
    objects = objects.concat(resp.items);
  }
  return objects;
};

export const uploadObject = async (objectName, buffer) => {
  await ensureBucketExists(apsBucket);
  const accessToken = await getInternalToken();
  const obj = await ossClient.uploadObject(apsBucket, objectName, buffer, { accessToken });
  return obj;
};

export const translateObject = async (urn, rootFilename) => {
  const accessToken = await getInternalToken();
  const job = await modelDerivativeClient.startJob(
    {
      input: {
        urn,
        compressedUrn: !!rootFilename,
        rootFilename,
      },
      output: {
        formats: [
          {
            views: [View._2d, View._3d],
            type: OutputType.Svf2,
          },
        ],
      },
    },
    { accessToken },
  );
  return job.result;
};

export const getManifest = async (urn) => {
  const accessToken = await getInternalToken();
  try {
    const manifest = await modelDerivativeClient.getManifest(urn, { accessToken });
    return manifest;
  } catch (err) {
    if (err.axiosError.response.status === 404) {
      return null;
    } else {
      throw err;
    }
  }
};

export const urnify = (id) => Buffer.from(id).toString('base64').replace(/=/g, '');
