import * as URI from "uri-js";

import type { Track } from "@applets/core/types.d.ts";
import { isAudioFile } from "@scripts/input/common";
import { bucketsFromTracks, buildURI, createClient, loadBuckets, parseURI } from "./common";
import { expose } from "@scripts/common";

////////////////////////////////////////////
// ACTIONS
////////////////////////////////////////////
const actions = expose({
  consult,
  contextualize,
  list,
  resolve,
});

export type Actions = typeof actions;

// Actions

async function consult(fileUriOrScheme: string) {
  if (!navigator.onLine)
    return { supported: false, reason: "Internet connection is not available" };

  // TODO: Check if bucket is available + CORS works?
  return { supported: true };
}

async function contextualize(tracks: Track[]) {
  return bucketsFromTracks(tracks);
}

async function list(cachedTracks: Track[] = []) {
  const cache = cachedTracks.reduce((acc: Record<string, Track>, t: Track) => {
    const uri = URI.parse(t.uri);
    if (!uri.path) return acc;
    return { ...acc, [URI.unescapeComponent(uri.path)]: t };
  }, {});

  const buckets = await loadBuckets();
  const promises = Object.values(buckets).map(async (bucket) => {
    const client = createClient(bucket);

    const list = await Array.fromAsync(
      client.listObjects({
        prefix: bucket.path.replace(/^\//, ""),
      }),
    );

    return list
      .filter((l) => isAudioFile(l.key))
      .map((l) => {
        const cachedTrack = cache[`/${l.key}`];

        const id = cachedTrack?.id || crypto.randomUUID();
        const stats = cachedTrack?.stats;
        const tags = cachedTrack?.tags;

        const track: Track = {
          id,
          stats,
          tags,
          uri: buildURI(bucket, l.key),
        };

        return track;
      });
  });

  return (await Promise.all(promises)).flat(1);
}

async function resolve({ method, uri }: { method: string; uri: string }) {
  const bucket = parseURI(uri);
  if (!bucket) return undefined;

  const client = createClient(bucket);
  const parsedURI = URI.parse(uri);
  const path = (
    bucket.path.replace(/\/$/, "") + URI.unescapeComponent(parsedURI.path || "")
  ).replace(/^\//, "");

  const expiresInSeconds = 60 * 60 * 24 * 7; // 7 days
  const expiresAtSeconds = Math.round(Date.now() / 1000) + expiresInSeconds;
  const url = await client.getPresignedUrl(method.toUpperCase() as any, path);

  return { expiresAt: expiresAtSeconds, url };
}
