/**
 * Client-side MP4 codec sniffing for upload validation.
 *
 * Why: uploads are stored and served as-is (no server transcoding), so a
 * 4K HEVC iPhone export plays on desktops with hardware HEVC decoders but
 * shows "Couldn't load this video" on most Android phones. The only fix at
 * the frontend level is to catch incompatible codecs before upload.
 */

export type VideoCodec = "h264" | "hevc" | "av1" | "vp9" | "unknown";

export interface VideoCompatResult {
  codec: VideoCodec;
  /** true when the codec plays on effectively every phone (H.264) */
  mobileCompatible: boolean;
  /** moov atom placed after mdat — slower startup, but still playable */
  moovAtEnd: boolean;
}

const COMPATIBLE: VideoCompatResult = {
  codec: "unknown",
  mobileCompatible: true,
  moovAtEnd: false,
};

/** fourcc → codec, ordered so the video track wins over audio noise */
const CODEC_TAGS: Array<[string, VideoCodec]> = [
  ["avc1", "h264"],
  ["avc3", "h264"],
  ["hvc1", "hevc"],
  ["hev1", "hevc"],
  ["av01", "av1"],
  ["vp09", "vp9"],
];

function findTag(bytes: Uint8Array, tag: string): number {
  const t = [tag.charCodeAt(0), tag.charCodeAt(1), tag.charCodeAt(2), tag.charCodeAt(3)];
  for (let i = 0; i <= bytes.length - 4; i++) {
    if (bytes[i] === t[0] && bytes[i + 1] === t[1] && bytes[i + 2] === t[2] && bytes[i + 3] === t[3]) {
      return i;
    }
  }
  return -1;
}

async function readSlice(file: File, start: number, end: number): Promise<Uint8Array> {
  const buf = await file.slice(start, Math.min(end, file.size)).arrayBuffer();
  return new Uint8Array(buf);
}

/**
 * Walk the top-level MP4 boxes to locate the moov atom, then scan it for the
 * sample-entry fourcc of the video track. Uses File.slice random access, so
 * only a few KB (plus the moov itself) is ever read — safe for multi-GB files.
 *
 * Returns `mobileCompatible: true` when in doubt (non-MP4 container, parse
 * failure, unknown codec) — the check must never block a valid upload.
 */
export async function checkVideoCompat(file: File): Promise<VideoCompatResult> {
  try {
    const head = await readSlice(file, 0, 12);
    // Only MP4/QuickTime family containers start with an ftyp box
    if (head.length < 12 || findTag(head.subarray(4, 8), "ftyp") !== 0) {
      return COMPATIBLE;
    }

    let offset = 0;
    let sawMdat = false;
    // Top-level box walk (bounded to avoid pathological files)
    for (let hop = 0; hop < 64 && offset + 16 <= file.size; hop++) {
      const hdr = await readSlice(file, offset, offset + 16);
      const view = new DataView(hdr.buffer, hdr.byteOffset, hdr.byteLength);
      let size = view.getUint32(0);
      const type = String.fromCharCode(hdr[4], hdr[5], hdr[6], hdr[7]);
      if (size === 1) {
        // 64-bit largesize
        size = Number(view.getBigUint64(8));
      } else if (size === 0) {
        size = file.size - offset; // box extends to EOF
      }
      if (size < 8) return COMPATIBLE;

      if (type === "mdat") sawMdat = true;
      if (type === "moov") {
        // moov is metadata-only; even for long videos it stays in the MBs
        const moov = await readSlice(file, offset, offset + Math.min(size, 16 * 1024 * 1024));
        for (const [tag, codec] of CODEC_TAGS) {
          if (findTag(moov, tag) >= 0) {
            return {
              codec,
              mobileCompatible: codec === "h264",
              moovAtEnd: sawMdat,
            };
          }
        }
        return { ...COMPATIBLE, moovAtEnd: sawMdat };
      }
      offset += size;
    }
    return COMPATIBLE;
  } catch {
    return COMPATIBLE;
  }
}

/** Human message for an incompatible upload, keyed by detected codec. */
export function incompatibleCodecMessage(codec: VideoCodec): string {
  const name =
    codec === "hevc" ? "HEVC (H.265)" : codec === "av1" ? "AV1" : "VP9";
  return `This video is encoded with ${name}, which most mobile devices can't play. Please export it as H.264 (standard MP4) and upload again.`;
}
