import {
  AV_PROJECT_SCHEMA_VERSION,
  type AvProjectV1,
  type BrowserFileIdentity,
  type CreateMediaAssetOptions,
  type CreateProjectOptions,
  type MediaAssetReference,
} from './project.types';

export function createEmptyProject(
  options: CreateProjectOptions = {}
): AvProjectV1 {
  const timestamp = options.timestamp ?? new Date().toISOString();
  if (!isIsoDate(timestamp)) {
    throw new TypeError('Project timestamp must be a valid ISO-8601 date.');
  }

  return {
    schemaVersion: AV_PROJECT_SCHEMA_VERSION,
    id: options.id ?? createProjectId(),
    name: options.name?.trim() || 'Untitled project',
    createdAt: timestamp,
    updatedAt: timestamp,
    assets: [],
    timeline: [],
    output: {
      presetId: options.output?.presetId ?? 'mp4-h264-balanced',
      fileName: options.output?.fileName ?? 'output.mp4',
      container: options.output?.container ?? 'mp4',
      videoEnabled: options.output?.videoEnabled ?? true,
      audioEnabled: options.output?.audioEnabled ?? true,
      ...(options.output?.width === undefined
        ? {}
        : { width: options.output.width }),
      ...(options.output?.height === undefined
        ? {}
        : { height: options.output.height }),
      ...(options.output?.frameRate === undefined
        ? {}
        : { frameRate: options.output.frameRate }),
      sampleRate: options.output?.sampleRate ?? 48_000,
      channelLayout: options.output?.channelLayout ?? 'stereo',
      missingAudioPolicy:
        options.output?.missingAudioPolicy ?? 'insert-silence',
    },
    metadata: {
      custom: {},
    },
    chapters: [],
    subtitles: [],
  };
}

export function createMediaAssetReference(
  file: BrowserFileIdentity,
  options: CreateMediaAssetOptions = {}
): MediaAssetReference {
  if (!file.name.trim()) {
    throw new TypeError('A source file must have a name.');
  }
  if (!Number.isSafeInteger(file.size) || file.size < 0) {
    throw new TypeError('A source file size must be a non-negative integer.');
  }
  if (!Number.isSafeInteger(file.lastModified) || file.lastModified < 0) {
    throw new TypeError(
      'A source last-modified time must be a non-negative integer.'
    );
  }
  return {
    id: options.id ?? createId('asset'),
    originalName: file.name,
    size: file.size,
    lastModified: file.lastModified,
    mimeType: file.type,
    sourceStatus: options.sourceStatus ?? 'attached',
    ...(options.probe === undefined ? {} : { probe: options.probe }),
    ...(options.hash === undefined ? {} : { hash: options.hash }),
  };
}

function createProjectId(): string {
  return createId('project');
}

function createId(prefix: string): string {
  if (
    typeof globalThis.crypto !== 'undefined' &&
    typeof globalThis.crypto.randomUUID === 'function'
  ) {
    return globalThis.crypto.randomUUID();
  }
  return `${prefix}-${Date.now().toString(36)}-${Math.random()
    .toString(36)
    .slice(2, 10)}`;
}

function isIsoDate(value: string): boolean {
  return (
    /^\d{4}-\d{2}-\d{2}T/.test(value) && Number.isFinite(Date.parse(value))
  );
}
