import { addDurations, subtractDurations } from '../media/duration';
import type {
  AvProjectV1,
  MediaAssetReference,
  TimelineClip,
} from './project.types';

export interface TimelineEntry {
  clip: TimelineClip;
  asset?: MediaAssetReference;
  timelineStartSeconds: number;
  timelineEndSeconds: number;
  durationSeconds: number;
}

export function selectAssetById(
  project: AvProjectV1,
  assetId: string
): MediaAssetReference | undefined {
  return project.assets.find((asset) => asset.id === assetId);
}

export function selectClipById(
  project: AvProjectV1,
  clipId: string
): TimelineClip | undefined {
  return project.timeline.find((clip) => clip.id === clipId);
}

export function selectClipDuration(clip: TimelineClip): number {
  return Math.max(
    0,
    subtractDurations(clip.sourceOutSeconds, clip.sourceInSeconds)
  );
}

export function selectTimelineDuration(project: AvProjectV1): number {
  return addDurations(project.timeline.map(selectClipDuration));
}

export function selectTimelineEntries(project: AvProjectV1): TimelineEntry[] {
  let cursor = 0;
  return project.timeline.map((clip) => {
    const durationSeconds = selectClipDuration(clip);
    const timelineStartSeconds = cursor;
    cursor = addDurations([cursor, durationSeconds]);
    return {
      clip,
      asset: selectAssetById(project, clip.assetId),
      timelineStartSeconds,
      timelineEndSeconds: cursor,
      durationSeconds,
    };
  });
}

export function selectMissingAssets(
  project: AvProjectV1
): MediaAssetReference[] {
  return project.assets.filter((asset) => asset.sourceStatus === 'missing');
}

export function selectAttachedAssets(
  project: AvProjectV1
): MediaAssetReference[] {
  return project.assets.filter((asset) => asset.sourceStatus === 'attached');
}

export function selectReferencedAssetIds(project: AvProjectV1): Set<string> {
  return new Set([
    ...project.timeline.map((clip) => clip.assetId),
    ...project.subtitles.flatMap((track) =>
      track.assetId === undefined ? [] : [track.assetId]
    ),
  ]);
}

export function selectUnusedAssets(
  project: AvProjectV1
): MediaAssetReference[] {
  const referenced = selectReferencedAssetIds(project);
  return project.assets.filter((asset) => !referenced.has(asset.id));
}

export function selectCanExport(project: AvProjectV1): {
  canExport: boolean;
  reasons: string[];
} {
  const reasons: string[] = [];
  if (project.timeline.length === 0) {
    reasons.push('The timeline is empty.');
  }
  const missingReferenced = selectMissingAssets(project).filter((asset) =>
    selectReferencedAssetIds(project).has(asset.id)
  );
  if (missingReferenced.length > 0) {
    reasons.push(
      `${missingReferenced.length} referenced source ${
        missingReferenced.length === 1 ? 'file is' : 'files are'
      } missing.`
    );
  }
  if (!project.output.videoEnabled && !project.output.audioEnabled) {
    reasons.push('No output stream type is enabled.');
  }
  return { canExport: reasons.length === 0, reasons };
}
