import type { Infer } from "@char/lexicon.ts";
import type { VideoLexiconUniverse } from "../common/lexicons.ts";

import { resolveDid, resolveHandle } from "../common/identity.ts";
import { VIDEO_PATTERN } from "../common/routes.ts";

import type { ATProtoUniverse } from "@char/lexicon.ts/atproto";
import { XRPC } from "@char/lexicon.ts/rpc";

type VideoRecord = Infer<VideoLexiconUniverse, "blue.cerulea.video.video">;

const fetchVideoRecord = async (
  did: string,
  rkey: string
): Promise<VideoRecord> => {
  const didDoc = await resolveDid(did);
  const pds = didDoc.service?.find((it) => it.id === "#atproto_pds")
    ?.serviceEndpoint as string | undefined;

  if (!pds) throw new Error("could not resolve pds for requested repo");

  const xrpc = new XRPC<ATProtoUniverse>(pds);
  const record = await xrpc.get("com.atproto.repo.getRecord", {
    parameters: {
      collection: "blue.cerulea.video.video",
      repo: did,
      rkey,
    },
  });

  // TODO: replace this cast with a lexicon.ts validation check
  return record.value as VideoRecord;
};

const resolveVideoURL = async (
  repo: `did:${string}`,
  blob: string
): Promise<string> => {
  try {
    const xrpc = new XRPC<VideoLexiconUniverse>(globalThis.location.href);
    const res = await xrpc.call("blue.cerulea.video.fetchVideo", {
      input: { repo, blob },
    });
    return `/user-content/${res.filename}`;
  } catch {
    throw new Error("got error fetching URL of video at CDN");
  }
};

const main = async () => {
  const player = document.querySelector("#player")! as HTMLElement;

  const location = VIDEO_PATTERN.exec(globalThis.location.href);
  if (!location) throw new Error("video pattern did not match url");
  const { repo, rkey } = location.pathname.groups as {
    repo: string;
    rkey: string;
  };

  const isDid = (s: string): s is `did:${string}` => s.startsWith("did:");
  const did = isDid(repo) ? repo : await resolveHandle(repo);

  const record = await fetchVideoRecord(did, rkey);
  const videoURL = await resolveVideoURL(
    did,
    "ref" in record.video ? record.video.ref.$link : record.video.cid
  );
  const video = (
    <video crossOrigin="anonymous" controls>
      <source src={videoURL} />
    </video>
  ) as HTMLVideoElement;
  video.volume = 0.8;

  player.append(video);

  if (record.title) {
    player.append(<h1>{record.title}</h1>);
    document.title = `${record.title} | video.cerulea.blue`;
  }
  if (record.description)
    player.append(<p className="description">{record.description}</p>);
};

main();
