/**
 * apple_makernotes.js — 完整 Apple MakerNotes 模板注入
 *
 * 参照 iPhone 15 Pro Max 原生 HEIC (apple.HEIC) 提取的 1788 字节 MakerNotes 模板，
 * 包含 29 个 Apple 私有字段：
 *   - MakerNoteVersion, RunTimeFlags/Value/Scale/Epoch
 *   - AEStable, AETarget, AEAverage, AFStable
 *   - AccelerationVector, FocusDistanceRange
 *   - **ContentIdentifier** (UUID, 36 字符 ASCII @1372)
 *   - ImageCaptureType
 *   - **LivePhotoVideoIndex** (int64, 8 字节 BE @1410)
 *   - PhotosAppFeatureFlags, HDRHeadroom
 *   - AFPerformance, SignalToNoiseRatio
 *   - **PhotoIdentifier** (UUID, 36 字符 ASCII @1494)
 *   - ColorTemperature, CameraType, FocusPosition, HDRGain
 *   - AFMeasuredDepth, AFConfidence
 *   - SemanticStyle (BPLIST)
 *
 * 实测：exiftool 能完整解析该模板的所有 29 个 Apple 标签。
 * 模板大小固定，所以可以直接覆写固定偏移的 UUID/时间戳字段。
 *
 * 同步：参考开源项目 https://github.com/AssassinJY/live_motion_photos_convert
 *       的 `makernotes_apple.bin`（同思路：从微信实况图预提取 MakerNotes 复用）。
 */

const TEMPLATE_BASE64 =
  'QXBwbGUgaU9TAAABTU0AOgABAAkAAAABAAAAEAACAAcAAAIAAAACzAADAAcAAABoAAAEzAAEAAkA' +
  'AAABAAAAAQAFAAkAAAABAAAAtgAGAAkAAAABAAAAtQAHAAkAAAABAAAAAQAIAAoAAAADAAAFNAAM' +
  'AAoAAAACAAAFTAANAAkAAAAB////9wAOAAkAAAABAAAAAAAQAAkAAAABAAAAAQARAAIAAAAlAAAF' +
  'XAAUAAkAAAABAAAADAAXABAAAAABAAAFggAZAAkAAAABAAIgAgAaAAIAAAAGAAAFigAfAAkAAAAB' +
  'AAAAAAAgAAIAAAAlAAAFkAAhAAoAAAABAAAFtgAjAAkAAAACAAAFvgAlABAAAAABAAAFxgAmAAkA' +
  'AAABAAAAAwAnAAoAAAABAAAFzgArAAIAAAAlAAAF1gAtAAkAAAABAAARdAAuAAkAAAABAAAAAQAv' +
  'AAkAAAABAAAA/wAwAAoAAAABAAAF/AA2AAkAAAABAAAAmgA3AAkAAAABAAAACAA4AAkAAAABAAAA' +
  'DwA5AAkAAAABAAAAAAA6AAkAAAABAAAAgAA7AAkAAAABAAAAAAA8AAkAAAABAAAABAA9AAkAAAAB' +
  'AAAAZAA/AAkAAAABAAAAAABAAAcAAABKAAAGBABBAAkAAAABAAAAAABCAAkAAAABAAAAAABDAAkA' +
  'AAABAAAAAABEAAkAAAABAAAAAABFAAkAAAABAAAAAABGAAkAAAABAAAAAABIAAkAAAABAAAAAABJ' +
  'AAkAAAABAAAAAABKAAkAAAABAAAAAgBNAAoAAAABAAAGTgBOAAcAAAB5AAAGVgBPAAcAAAArAAAG' +
  '0ABSAAkAAAABAAAAAQBTAAkAAAABAAAAAQBVAAkAAAABAAAAAABYAAkAAAABAAAIAwBeAAEAAAAE' +
  'YnBsaQBgAAkAAAABAAAPsQBhAAkAAAABAAAAGAAAAACZAI0AegB0AfEBIQL+AbEBmgGSAYIBcwG0' +
  'AFgAWwBdAJcAjQCvABEC8gGqAbgBIQH7AOcAQgFeASsBWgBaAFwAlwCNAFEB/wH+AbABOAEYASIB' +
  '+ADTABkBOQGUAFkAXACaAIsAyQHRAb8BHgEvAesA/gD3AMQAoQARAc8AWABcAKAApADCAboBRQE2' +
  'AREB0wCyALkAlgBmAN8A7wBYAF0ApADaAKQBlAEuATABLgGPADYANQA5AG4AmwAGAVcAXQCnAPMA' +
  'iQFqAV4BLwHBADwALgAsADIAUACrAAgBYABeAK4A+gBuAVwBVgEeAXcANwAwADwALgBdAL8A+gBl' +
  'AF8ApQDsAFYBTgEvAQwBXQA7AD8ALwA3AHAAqwDyAGQAbwCqANMAOgEdAekAvwBsADYANwA6ADcA' +
  'lwCyAOsAZwCAALQAswAdAQUByQCKAHwASABMAFAAPwCZALoA3gBpAHUAugCbAAoB2wCmAHQAaABA' +
  'AEEAWwCMAJ0AzADJAGsAcADCAKUA6wDBAJMAcgBgAHIAdgByAKcAqgDTAKIAbABxAM0AsgDdALUA' +
  'jwB5AGcAZgB9AGkAcACtAOoAdQBzAHYA2gDCAM0AzwCSAIIAcwBnAF8AaACCAMUAxgCIAHcAegDj' +
  'AM4A6gDZALEAigCBAHsAewCCAKYA3ACNAJQAfgB8AGJwbGlzdDAw1AECAwQFBgcIVWZsYWdzVXZh' +
  'bHVlWXRpbWVzY2FsZVVlcG9jaBABEwAAnoSxeggXEjuaygAQAAgRFx0nLS84PQAAAAAAAAEBAAAA' +
  'AAAAAAkAAAAAAAAAAAAAAAAAAAA////1bwAH8hb//4CZAAEOVP//NzoAAOmlAAAC0QAAAQAAAAA3' +
  'AAABAEYwOEM0RDI5LUNENkEtNDdEOS05MjAwLTAyQkQxOUQ5RjNGMgAAAAAAAgBQICRxNzUwbgA3' +
  'MENFQUY2OS1BNUE0LTQ5QzgtQkE3NC0yNjg3MkU5NURDNjcAAAAQKKoAD/+1AAAAERAAADAAAAAA' +
  'EvAUjgAElUoAAB/zQ0UxRDMzNUEtRkJCQi00ODY2LUEwN0MtMzhDQ0U1NjFFRUE1AAAAACYzAAGi' +
  'zWJwbGlzdDAw1AECAwQFBgYHUTNRMVEyUTAQACIAAAAAEAEIERMVFxkbIAAAAAAAAAEBAAAAAAAA' +
  'AAgAAAAAAAAAAAAAAAAAAAAiAAl/zQAAQABicGxpc3QwMNIBAgMEUTFRMhABogUK0gYHCAlTMi4x' +
  'UzIuMiNASQSVAAAAACNA77wgAAAAANIGBwsMIwAAAAAAAAAAI0AwAAAAAAAACA0PERMWGx8jLDU6' +
  'QwAAAAAAAAEBAAAAAAAAAA0AAAAAAAAAAAAAAAAAAABMAGJwbGlzdDAwEAAIAAAAAAAAAQEAAAAA' +
  'AAAAAQAAAAAAAAAAAAAAAAAAAAoA';

const TEMPLATE_BYTES = (() => {
  if (typeof atob === 'function') {
    const bin = atob(TEMPLATE_BASE64);
    const out = new Uint8Array(bin.length);
    for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
    return out;
  }
  // Node fallback (Jest/Node tests)
  return new Uint8Array(Buffer.from(TEMPLATE_BASE64, 'base64'));
})();

// Apple epoch: 2001-01-01T00:00:00Z (Unix epoch in seconds = 978307200)
// LivePhotoVideoIndex 单位 = nanoseconds since Apple epoch（来自 Apple CoreMedia CMTime）
const APPLE_EPOCH_UNIX_SEC = 978307200;

/** 把 Date 转换为 Apple LivePhotoVideoIndex (int64 BE, nanoseconds)
 *  必须用 BigInt：纳秒数 ≈ 10^18 超出 Number.MAX_SAFE_INTEGER (2^53 ≈ 9×10^15)，
 *  用 Number 会精度丢失（表现为 LPVI 显示 ~25 年后的时间戳）。 */
function dateToLivePhotoVideoIndex(date) {
  const msBig = BigInt(date.getTime());
  const appleEpochSec = BigInt(APPLE_EPOCH_UNIX_SEC);
  const unixSec = msBig / 1000n;
  const subMs = msBig - unixSec * 1000n;
  return unixSec * 1_000_000_000n - appleEpochSec * 1_000_000_000n + subMs * 1_000_000n;
}

/** 固定偏移（依据 exiftool 解析 apple.HEIC 的 MakerNotes 实测） */
const OFFSET_CONTENT_IDENTIFIER = 1372; // 36 字节 ASCII
const OFFSET_PHOTO_IDENTIFIER = 1494;   // 36 字节 ASCII
const OFFSET_LIVE_PHOTO_VIDEO_INDEX = 1410; // 8 字节 BE int64

/**
 * 基于完整 Apple MakerNotes 模板，生成指定 ContentIdentifier / PhotoIdentifier /
 * LivePhotoVideoIndex 的 MakerNotes 二进制块。
 *
 * @param {string} contentUuid  36 字符 ContentIdentifier（与 MOV 的 QuickTime Keys ContentIdentifier 一致）
 * @param {string} photoUuid    36 字符 PhotoIdentifier（区分照片本身的 UUID，可与 contentUuid 不同）
 * @param {Date}   photoDate    拍摄时间，用于 LivePhotoVideoIndex；缺省时使用当前时间
 * @returns {Uint8Array} 1788 字节的 MakerNotes 二进制
 */
export function buildAppleMakerNote(contentUuid, photoUuid, photoDate) {
  if (!/^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/.test(contentUuid)) {
    throw new Error('contentUuid 必须是 36 字符 UUID 大写字符串');
  }
  if (!/^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/.test(photoUuid)) {
    throw new Error('photoUuid 必须是 36 字符 UUID 大写字符串');
  }

  const out = new Uint8Array(TEMPLATE_BYTES); // 复制模板
  // 覆写 ContentIdentifier（36 字节 ASCII）
  for (let i = 0; i < 36; i++) out[OFFSET_CONTENT_IDENTIFIER + i] = contentUuid.charCodeAt(i);
  // 覆写 PhotoIdentifier
  for (let i = 0; i < 36; i++) out[OFFSET_PHOTO_IDENTIFIER + i] = photoUuid.charCodeAt(i);
  // 覆写 LivePhotoVideoIndex（8 字节 BE int64，必须用 BigInt 保证精度）
  const lpvi = dateToLivePhotoVideoIndex(photoDate || new Date());
  // lpvi 是 BigInt，单位 ns；拆成 high/low 各 32 位写入大端 8 字节
  const mask32 = 0xffffffffn;
  const high = Number((lpvi >> 32n) & mask32); // BigInt 算术右移后取低 32 位
  const low = Number(lpvi & mask32);
  out[OFFSET_LIVE_PHOTO_VIDEO_INDEX]     = (high >>> 24) & 0xff;
  out[OFFSET_LIVE_PHOTO_VIDEO_INDEX + 1] = (high >>> 16) & 0xff;
  out[OFFSET_LIVE_PHOTO_VIDEO_INDEX + 2] = (high >>> 8) & 0xff;
  out[OFFSET_LIVE_PHOTO_VIDEO_INDEX + 3] = high & 0xff;
  out[OFFSET_LIVE_PHOTO_VIDEO_INDEX + 4] = (low >>> 24) & 0xff;
  out[OFFSET_LIVE_PHOTO_VIDEO_INDEX + 5] = (low >>> 16) & 0xff;
  out[OFFSET_LIVE_PHOTO_VIDEO_INDEX + 6] = (low >>> 8) & 0xff;
  out[OFFSET_LIVE_PHOTO_VIDEO_INDEX + 7] = low & 0xff;
  return out;
}

export const APPLE_MAKERNOTES_TEMPLATE_SIZE = TEMPLATE_BYTES.length;
