// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

import type { AttachmentForUIType } from '../types/Attachment.std.ts';
import { getUrl } from '../util/Attachment.std.ts';
import { MediaTier } from '../types/AttachmentDownload.std.ts';
import { missingCaseError } from '../util/missingCaseError.std.ts';
import { getAttachmentCiphertextSize } from '../util/AttachmentCrypto.std.ts';
import { useDelayedValue } from './useDelayedValue.std.ts';

const TRANSITION_DELAY = 200;

type InternalState = 'NeedsDownload' | 'Downloading' | 'ReadyToShow';

export type AttachmentStatusType = Readonly<
  | {
      state: 'NeedsDownload';
    }
  | {
      state: 'Downloading';
      totalDownloaded: number | undefined;
      size: number;
    }
  | {
      state: 'ReadyToShow';
    }
>;

export function useAttachmentStatus(
  attachment: AttachmentForUIType
): AttachmentStatusType;

export function useAttachmentStatus(
  attachment: AttachmentForUIType | undefined
): AttachmentStatusType | undefined;

export function useAttachmentStatus(
  attachment: AttachmentForUIType | undefined
): AttachmentStatusType | undefined {
  const isAttachmentNotAvailable =
    attachment == null ||
    (attachment.isPermanentlyUndownloadable && !attachment.wasTooBig);

  const url = attachment == null ? undefined : getUrl(attachment);

  let nextState: InternalState = 'ReadyToShow';
  if (attachment && isAttachmentNotAvailable) {
    nextState = 'ReadyToShow';
  } else if (attachment && url == null && !attachment.pending) {
    nextState = 'NeedsDownload';
  } else if (attachment && url == null && attachment.pending) {
    nextState = 'Downloading';
  }

  const state = useDelayedValue(nextState, TRANSITION_DELAY);

  if (attachment == null) {
    return undefined;
  }

  // Idle
  if (state === 'NeedsDownload' && nextState === state) {
    return { state: 'NeedsDownload' };
  }

  const { size: unpaddedPlaintextSize, totalDownloaded } = attachment;
  const size = getAttachmentCiphertextSize({
    unpaddedPlaintextSize,
    mediaTier: MediaTier.STANDARD,
  });

  // Transition
  if (state !== nextState) {
    if (nextState === 'NeedsDownload') {
      return { state: 'NeedsDownload' };
    }

    if (nextState === 'Downloading') {
      return { state: 'Downloading', size, totalDownloaded };
    }

    if (nextState === 'ReadyToShow') {
      return { state: 'Downloading', size, totalDownloaded: size };
    }

    throw missingCaseError(nextState);
  }

  if (state === 'NeedsDownload') {
    return { state: 'NeedsDownload' };
  }

  if (state === 'Downloading') {
    return { state: 'Downloading', size, totalDownloaded };
  }

  if (state === 'ReadyToShow') {
    return { state: 'ReadyToShow' };
  }

  throw missingCaseError(state);
}
