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

import type { LocalizerType } from '../types/Util.std.ts';
import {
  CallMode,
  CallDirection,
  DirectCallStatus,
  CallType,
  GroupCallStatus,
} from '../types/CallDisposition.std.ts';
import type {
  CallStatus,
  CallHistoryDetails,
} from '../types/CallDisposition.std.ts';
import { missingCaseError } from './missingCaseError.std.ts';
import type { ConversationType } from '../state/ducks/conversations.preload.ts';
import { strictAssert } from './assert.std.ts';
import { isMoreRecentThan } from './timestamp.std.ts';
import { MINUTE } from './durations/index.std.ts';

export type CallingNotificationType = Readonly<{
  // In some older calls, we don't have a call id, this hardens against that.
  callHistory: CallHistoryDetails | null;
  callCreator: ConversationType | null;
  activeConversationId: string | null;
  groupCallEnded: boolean | null;
  deviceCount: number;
  maxDevices: number;
  isSelectMode: boolean;
  isTargeted: boolean;
}>;

export function getDirectCallNotificationText(
  callDirection: CallDirection,
  callType: CallType,
  callStatus: DirectCallStatus,
  i18n: LocalizerType
): string {
  if (
    callStatus === DirectCallStatus.Pending ||
    callStatus === DirectCallStatus.Unknown
  ) {
    if (callDirection === CallDirection.Incoming) {
      return callType === CallType.Video
        ? i18n('icu:incomingVideoCall')
        : i18n('icu:incomingAudioCall');
    }
    return callType === CallType.Video
      ? i18n('icu:outgoingVideoCall')
      : i18n('icu:outgoingAudioCall');
  }

  if (callStatus === DirectCallStatus.Accepted) {
    if (callDirection === CallDirection.Incoming) {
      return callType === CallType.Video
        ? i18n('icu:acceptedIncomingVideoCall')
        : i18n('icu:acceptedIncomingAudioCall');
    }
    return callType === CallType.Video
      ? i18n('icu:acceptedOutgoingVideoCall')
      : i18n('icu:acceptedOutgoingAudioCall');
  }

  if (callStatus === DirectCallStatus.Declined) {
    if (callDirection === CallDirection.Incoming) {
      return callType === CallType.Video
        ? i18n('icu:declinedIncomingVideoCall')
        : i18n('icu:declinedIncomingAudioCall');
    }
    return callType === CallType.Video
      ? i18n('icu:missedOrDeclinedOutgoingVideoCall')
      : i18n('icu:missedOrDeclinedOutgoingAudioCall');
  }

  if (
    callStatus === DirectCallStatus.Missed ||
    callStatus === DirectCallStatus.MissedNotificationProfile
  ) {
    if (callDirection === CallDirection.Incoming) {
      return callType === CallType.Video
        ? i18n('icu:missedIncomingVideoCall')
        : i18n('icu:missedIncomingAudioCall');
    }
    return callType === CallType.Video
      ? i18n('icu:missedOrDeclinedOutgoingVideoCall')
      : i18n('icu:missedOrDeclinedOutgoingAudioCall');
  }

  if (callStatus === DirectCallStatus.Deleted) {
    throw new Error(
      'getDirectCallNotificationText: Cannot render deleted call'
    );
  }

  throw missingCaseError(callStatus);
}

function getGroupCallNotificationText({
  groupCallEnded,
  creator,
  callHistory,
  i18n,
}: {
  groupCallEnded: boolean;
  creator: ConversationType | null;
  callHistory: CallHistoryDetails;
  i18n: LocalizerType;
}): string {
  if (groupCallEnded) {
    const { direction, status, timestamp } = callHistory;
    if (direction === CallDirection.Incoming) {
      if (status === GroupCallStatus.Declined) {
        return i18n('icu:CallHistory__DescriptionVideoCall--Declined');
      }
      if (status === GroupCallStatus.Missed) {
        return i18n('icu:CallHistory__DescriptionVideoCall--Missed');
      }
      if (isMoreRecentThan(timestamp, 5 * MINUTE)) {
        return i18n('icu:calling__call-notification__ended');
      }
      return i18n('icu:acceptedIncomingVideoCall');
    }

    // Outgoing ended group calls
    if (isMoreRecentThan(timestamp, 5 * MINUTE)) {
      return i18n('icu:calling__call-notification__ended');
    }
    return i18n('icu:acceptedOutgoingVideoCall');
  }

  // TODO: Active call with participants DESKTOP-7439

  if (creator == null) {
    return i18n('icu:calling__call-notification__started-by-someone');
  }
  if (creator.isMe) {
    return i18n('icu:calling__call-notification__started-by-you');
  }
  return i18n('icu:calling__call-notification__started', {
    name: creator.systemGivenName ?? creator.title,
  });
}

export function getCallingNotificationText(
  callingNotification: CallingNotificationType,
  i18n: LocalizerType
): string | null {
  const {
    callHistory,
    callCreator: creator,
    groupCallEnded,
  } = callingNotification;
  if (callHistory == null) {
    return null;
  }

  if (callHistory.mode === CallMode.Direct) {
    return getDirectCallNotificationText(
      callHistory.direction,
      callHistory.type,
      callHistory.status as DirectCallStatus,
      i18n
    );
  }
  if (callHistory.mode === CallMode.Group) {
    strictAssert(
      groupCallEnded != null,
      'getCallingNotificationText: groupCallEnded shouldnt be null for a group call'
    );
    return getGroupCallNotificationText({
      groupCallEnded,
      creator,
      callHistory,
      i18n,
    });
  }
  if (callHistory.mode === CallMode.Adhoc) {
    return null;
  }
  throw missingCaseError(callHistory.mode);
}

type CallingIconType =
  | 'audio-incoming'
  | 'audio-missed'
  | 'audio-outgoing'
  | 'phone'
  | 'video'
  | 'video-incoming'
  | 'video-missed'
  | 'video-outgoing';

export function getCallingIcon(
  callType: CallType,
  callDirection: CallDirection,
  callStatus: CallStatus
): CallingIconType {
  if (callType === CallType.Audio) {
    if (callStatus === DirectCallStatus.Accepted) {
      return callDirection === CallDirection.Incoming
        ? 'audio-incoming'
        : 'audio-outgoing';
    }
    if (
      callStatus === DirectCallStatus.Missed ||
      callStatus === DirectCallStatus.Declined
    ) {
      return 'audio-missed';
    }
    return 'phone';
  }
  if (callType === CallType.Video) {
    if (callStatus === DirectCallStatus.Accepted) {
      return callDirection === CallDirection.Incoming
        ? 'video-incoming'
        : 'video-outgoing';
    }
    if (
      callStatus === DirectCallStatus.Missed ||
      callStatus === DirectCallStatus.Declined
    ) {
      return 'video-missed';
    }
    return 'video';
  }
  if (callType === CallType.Group || callType === CallType.Adhoc) {
    return 'video';
  }
  if (callType === CallType.Unknown) {
    return 'video';
  }
  throw missingCaseError(callType);
}
