import { splitFileName } from '../media/safe-file-name';

const MIME_BY_EXTENSION: Readonly<Record<string, string>> = Object.freeze({
  '.3gp': 'video/3gpp',
  '.aac': 'audio/aac',
  '.ass': 'text/x-ssa',
  '.avi': 'video/x-msvideo',
  '.avif': 'image/avif',
  '.bmp': 'image/bmp',
  '.flac': 'audio/flac',
  '.gif': 'image/gif',
  '.jpeg': 'image/jpeg',
  '.jpg': 'image/jpeg',
  '.json': 'application/json',
  '.m2ts': 'video/mp2t',
  '.m4a': 'audio/mp4',
  '.m4v': 'video/mp4',
  '.mkv': 'video/x-matroska',
  '.mov': 'video/quicktime',
  '.mp3': 'audio/mpeg',
  '.mp4': 'video/mp4',
  '.mpeg': 'video/mpeg',
  '.mpg': 'video/mpeg',
  '.oga': 'audio/ogg',
  '.ogg': 'audio/ogg',
  '.ogv': 'video/ogg',
  '.opus': 'audio/ogg',
  '.png': 'image/png',
  '.srt': 'application/x-subrip',
  '.tif': 'image/tiff',
  '.tiff': 'image/tiff',
  '.ts': 'video/mp2t',
  '.txt': 'text/plain',
  '.vtt': 'text/vtt',
  '.wav': 'audio/wav',
  '.webm': 'video/webm',
  '.webp': 'image/webp',
  '.zip': 'application/zip',
});

const EXTENSION_BY_MIME: Readonly<Record<string, string>> = Object.freeze({
  'application/json': '.json',
  'application/zip': '.zip',
  'application/x-subrip': '.srt',
  'audio/aac': '.aac',
  'audio/flac': '.flac',
  'audio/mp4': '.m4a',
  'audio/mpeg': '.mp3',
  'audio/ogg': '.ogg',
  'audio/wav': '.wav',
  'image/avif': '.avif',
  'image/bmp': '.bmp',
  'image/gif': '.gif',
  'image/jpeg': '.jpg',
  'image/png': '.png',
  'image/tiff': '.tiff',
  'image/webp': '.webp',
  'text/plain': '.txt',
  'text/vtt': '.vtt',
  'text/x-ssa': '.ass',
  'video/3gpp': '.3gp',
  'video/mp2t': '.ts',
  'video/mp4': '.mp4',
  'video/mpeg': '.mpeg',
  'video/ogg': '.ogv',
  'video/quicktime': '.mov',
  'video/webm': '.webm',
  'video/x-matroska': '.mkv',
  'video/x-msvideo': '.avi',
});

const MIME_TYPE_PATTERN = /^[a-z0-9!#$&^_.+-]+\/[a-z0-9!#$&^_.+-]+$/iu;

export const BINARY_MIME_TYPE = 'application/octet-stream';
export const ZIP_MIME_TYPE = 'application/zip';
export const JSON_MIME_TYPE = 'application/json';

export function mimeTypeFromOutputName(fileName: string): string | undefined {
  const extension = splitFileName(fileName).extension.toLowerCase();
  return MIME_BY_EXTENSION[extension];
}

/**
 * Returns a picker- and Blob-safe base MIME type. Parameters such as codecs
 * are deliberately removed because the File System Access API accept map
 * expects media types, not Content-Type header values.
 */
export function normalizeOutputMimeType(
  candidate: string | undefined,
  fileName?: string
): string {
  const baseType = candidate?.split(';', 1)[0]?.trim().toLowerCase();
  if (baseType && MIME_TYPE_PATTERN.test(baseType)) {
    return baseType;
  }
  return (
    (fileName ? mimeTypeFromOutputName(fileName) : undefined) ??
    BINARY_MIME_TYPE
  );
}

export function preferredExtensionForMimeType(
  mimeType: string
): string | undefined {
  return EXTENSION_BY_MIME[normalizeOutputMimeType(mimeType)];
}

export function isBrowserPreviewMimeType(mimeType: string): boolean {
  const normalized = normalizeOutputMimeType(mimeType);
  return (
    normalized.startsWith('audio/') ||
    normalized.startsWith('video/') ||
    normalized.startsWith('image/')
  );
}

export function blobWithOutputMimeType(
  data: Blob | Uint8Array,
  mimeType: string,
  fileName?: string
): Blob {
  const normalized = normalizeOutputMimeType(mimeType, fileName);
  if (data instanceof Blob && data.type === normalized) {
    return data;
  }
  const part: BlobPart = data instanceof Blob ? data : Uint8Array.from(data);
  return new Blob([part], { type: normalized });
}
