import { enforce_nonnull } from "http://172.16.0.12/bladerunner_sdk/vscript@2.5.2/deno/release/mod.ts";
export function strip_header(sdp: string): string {
  const i = sdp.search(/^\s*m\s*=/m);
  return i === -1 ? "" : sdp.substring(i).trim();
}
export function extract_header(sdp: string): string {
  const i = sdp.search(/^\s*m\s*=/m);
  return (i === -1 ? sdp : sdp.substring(0, i)).trim();
}
export function sdp_is_empty(sdp: string) {
  return split_sdp(sdp).media_descriptions.length === 0;
}
export interface MediaDescription {
  dst: string;
  port: number;
  src: string;
  text: string;
  rtpmap: { payload: number; type: string };
  fmtp?: string;
  mid?: string;
}
function split_media_description(text: string): MediaDescription {
  const m = text.match(/^\s*a=mid:(.*)$/m);
  const mid = m?.[1].trim();
  const [dst, src] = enforce_nonnull(
    text.match(/^\s*a\s*=\s*source-filter\s*:\s*incl IN IP4 (.+) (.+)\s*$/m),
  ).slice(1, 3);
  const fmtp = text.match(/^\s*a\s*=\s*fmtp\s*\:(.*)$/m)?.[1]?.trim();
  const rtpmap = enforce_nonnull(
    text.match(/^\s*a\s*=\s*rtpmap\s*:\s*([0-9]+)\s+(.*)$/m),
  );
  const port = parseInt(
    enforce_nonnull(text.match(/^m=[a-z]+ ([0-9]+) /)?.[1]?.trim()),
    10,
  );
  return {
    dst: enforce_nonnull(dst),
    fmtp,
    mid,
    port,
    rtpmap: {
      payload: parseInt(enforce_nonnull(rtpmap[1]), 10),
      type: enforce_nonnull(rtpmap[2]).trim(),
    },
    src: enforce_nonnull(src),
    text,
  };
}
export interface SplitSDP {
  header: string;
  media_descriptions: MediaDescription[];
}
export function split_sdp(sdp: string): SplitSDP {
  const header = extract_header(sdp);
  let rest = strip_header(sdp);
  const media_descriptions: MediaDescription[] = [];
  while (rest.length !== 0) {
    const m = enforce_nonnull(
      rest.match(/^(m=[.\s\S]+?)(\n\s*m=[.\s\S]*)?\s*$/),
    );
    media_descriptions.push(split_media_description(enforce_nonnull(m[1])));
    rest = (m[2] ?? "").trim();
  }
  return { header, media_descriptions };
}
export function assemble_sdp(sdp: SplitSDP): string {
  return `${sdp.header}\n${sdp.media_descriptions
    .map((md) => md.text)
    .join("\n")}`;
}
export function merge_sdps(sdps: string[]): string {
  let result = sdps[0]?.trimRight() ?? "";
  for (let i = 1; i < sdps.length; ++i) {
    result += "\n" + strip_header(enforce_nonnull(sdps[i]));
  }
  return result;
}
export function sprinkle_fmtps(sdp: string): string {
  let state: "pick-up" | "drop" = "drop";
  let cur_fmtp = "";
  let result = "";
  for (const line of sdp.split(/\s*\n/)) {
    result += line.trim() + "\r\n";
    // relies on rtpmap preceding fmtp; not good but compatible with what our transmitter emits;
    // should replace string processing by actual SDP parsing
    if (line.match(/^\s*a\s*=\s*fmtp:/) && state === "pick-up") {
      cur_fmtp = line.trim();
    } else if (
      line.match(/^\s*a\s*=\s*rtpmap.*smpte291\/90000/) &&
      cur_fmtp.length !== 0
    ) {
      result += cur_fmtp + "\r\n";
    } else if (line.match(/^\s*a\s*=\s*rtpmap/)) {
      state = "pick-up";
      cur_fmtp = "";
    }
  }
  return result;
}
export function filter_mid(sdp: string, mid: string): string {
  const parts = split_sdp(sdp);
  let result = parts.header;
  for (const md of parts.media_descriptions) {
    if (md.mid === mid) {
      result += "\n";
      result += md.text;
    }
  }
  return result;
}
