import {
  ApiAudio, ApiMediaFormat, ApiMessage, ApiMessageSearchType, ApiPhoto, ApiVideo,
} from '../../api/types';

import { IS_OPUS_SUPPORTED, IS_PROGRESSIVE_SUPPORTED, IS_SAFARI } from '../../util/environment';
import { getMessageKey, isMessageLocal, matchLinkInMessageText } from './messages';
import { getDocumentHasPreview } from '../../components/common/helpers/documentInfo';

export type IDimensions = {
  width: number;
  height: number;
};

type Target = 'micro' | 'pictogram' | 'inline' | 'viewerPreview' | 'viewerFull' | 'download';


export function getMessageContent(message: ApiMessage) {
  return message.content;
}

export function hasMessageMedia(message: ApiMessage) {
  return Boolean((
    getMessagePhoto(message)
    || getMessageVideo(message)
    || getMessageDocument(message)
    || getMessageSticker(message)
    || getMessageContact(message)
    || getMessagePoll(message)
    || getMessageAction(message)
    || getMessageAudio(message)
    || getMessageVoice(message)
  ));
}

export function getMessagePhoto(message: ApiMessage) {
  return message.content.photo;
}

export function getMessageVideo(message: ApiMessage) {
  return message.content.video;
}

export function getMessageRoundVideo(message: ApiMessage) {
  const { video } = message.content;

  return video && video.isRound ? video : undefined;
}

export function getMessageAction(message: ApiMessage) {
  return message.content.action;
}

export function getMessageAudio(message: ApiMessage) {
  return message.content.audio;
}

export function getMessageVoice(message: ApiMessage) {
  return message.content.voice;
}

export function getMessageSticker(message: ApiMessage) {
  return message.content.sticker;
}

export function getMessageDocument(message: ApiMessage) {
  return message.content.document;
}

export function getMessageContact(message: ApiMessage) {
  return message.content.contact;
}

export function getMessagePoll(message: ApiMessage) {
  return message.content.poll;
}

export function getMessageInvoice(message: ApiMessage) {
  return message.content.invoice;
}

export function getMessageWebPage(message: ApiMessage) {
  return message.content.webPage;
}

export function getMessageWebPagePhoto(message: ApiMessage) {
  const webPage = getMessageWebPage(message);
  return webPage ? webPage.photo : undefined;
}

export function getMessageWebPageDocument(message: ApiMessage) {
  const webPage = getMessageWebPage(message);
  return webPage ? webPage.document : undefined;
}

export function getMessageWebPageVideo(message: ApiMessage): ApiVideo | undefined {
  const webPage = getMessageWebPage(message);
  if (!webPage) return undefined;
  return webPage.video;
}

export function getMessageMediaThumbnail(message: ApiMessage) {
  const media = getMessagePhoto(message)
    || getMessageVideo(message)
    || getMessageDocument(message)
    || getMessageSticker(message)
    || getMessageWebPagePhoto(message)
    || getMessageWebPageVideo(message);

  if (!media) {
    return undefined;
  }

  return media.thumbnail;
}

export function getMessageMediaThumbDataUri(message: ApiMessage) {
  const thumbnail = getMessageMediaThumbnail(message);

  return thumbnail ? thumbnail.dataUri : undefined;
}

export function getMessageMediaHash(
  message: ApiMessage,
  target: Target,
) {
  const {
    photo, video, sticker, audio, voice, document,
  } = message.content;
  const webPagePhoto = getMessageWebPagePhoto(message);
  const webPageVideo = getMessageWebPageVideo(message);

  const messageVideo = video || webPageVideo;
  const messagePhoto = photo || webPagePhoto;

  if (!(messagePhoto || messageVideo || sticker || audio || voice || document)) {
    return undefined;
  }

  const base = getMessageKey(message);

  if (messageVideo) {
    switch (target) {
      case 'micro':
      case 'pictogram':
        return `${base}?size=m`;
      case 'inline':
        return !hasMessageLocalBlobUrl(message) ? getVideoOrAudioBaseHash(messageVideo, base) : undefined;
      case 'viewerPreview':
        return `${base}?size=m`;
      case 'viewerFull':
        return getVideoOrAudioBaseHash(messageVideo, base);
      case 'download':
        return `${base}?download`;
    }
  }

  if (messagePhoto) {
    switch (target) {
      case 'micro':
      case 'pictogram':
        return `${base}?size=m`;
      case 'inline':
        if (hasMessageLocalBlobUrl(message)) {
          return undefined;
        }

        return `${base}?size=x`;
      case 'viewerPreview':
        return `${base}?size=x`;
      case 'viewerFull':
        return `${base}?size=z`;
    }
  }

  if (document) {
    switch (target) {
      case 'micro':
      case 'pictogram':
      case 'inline':
        if (!getDocumentHasPreview(document) || hasMessageLocalBlobUrl(message)) {
          return undefined;
        }

        return `${base}?size=m`;
      default:
        return base;
    }
  }

  if (sticker) {
    switch (target) {
      case 'micro':
        return undefined;
      case 'pictogram':
        return `${base}?size=m`;
      default:
        return base;
    }
  }

  if (audio) {
    switch (target) {
      case 'micro':
      case 'pictogram':
        return undefined;
      case 'download':
        return `${base}?download`;
      default:
        return getVideoOrAudioBaseHash(audio, base);
    }
  }

  if (voice) {
    switch (target) {
      case 'micro':
      case 'pictogram':
        return undefined;
      default:
        return base;
    }
  }

  return undefined;
}

function getVideoOrAudioBaseHash(media: ApiAudio | ApiVideo, base: string) {
  if (IS_PROGRESSIVE_SUPPORTED && IS_SAFARI) {
    return `${base}?fileSize=${media.size}&mimeType=${media.mimeType}`;
  }

  return base;
}

export function getMessageMediaFormat(
  message: ApiMessage, target: Target,
): Exclude<ApiMediaFormat, ApiMediaFormat.Lottie>;
export function getMessageMediaFormat(message: ApiMessage, target: Target, canBeLottie: true): ApiMediaFormat;
export function getMessageMediaFormat(
  message: ApiMessage, target: Target,
): ApiMediaFormat {
  const {
    sticker, video, audio, voice,
  } = message.content;

  const fullVideo = video || getMessageWebPageVideo(message);

  if (sticker && target === 'inline' && sticker.isAnimated) {
    return ApiMediaFormat.Lottie;
  } else if (fullVideo && IS_PROGRESSIVE_SUPPORTED && (
    target === 'viewerFull' || target === 'inline'
  )) {
    return ApiMediaFormat.Progressive;
  } else if (audio || voice) {
    // Safari
    if (voice && !IS_OPUS_SUPPORTED) {
      return ApiMediaFormat.BlobUrl;
    }

    return ApiMediaFormat.Progressive;
  }

  return ApiMediaFormat.BlobUrl;
}

export function getMessageMediaFilename(message: ApiMessage) {
  const { photo, video } = message.content;
  const webPagePhoto = getMessageWebPagePhoto(message);
  const webPageVideo = getMessageWebPageVideo(message);

  if (photo || webPagePhoto) {
    return `photo${message.date}.jpeg`;
  }

  if (webPageVideo) {
    return webPageVideo.fileName;
  }

  if (video) {
    return video.fileName;
  }

  return undefined;
}

export function hasMessageLocalBlobUrl(message: ApiMessage) {
  const { photo, video, document } = message.content;

  return (photo && photo.blobUrl) || (video && video.blobUrl) || (document && document.previewBlobUrl);
}

export function getChatMediaMessageIds(
  messages: Record<number, ApiMessage>, listedIds: number[], reverseOrder = false,
) {
  const ids = getMessageContentIds(messages, listedIds, 'media');

  return reverseOrder ? ids.reverse() : ids;
}

export function getPhotoFullDimensions(photo: ApiPhoto): IDimensions | undefined {
  return (
    photo.sizes.find((size) => size.type === 'z')
    || photo.sizes.find((size) => size.type === 'y')
    || getPhotoInlineDimensions(photo)
  );
}

export function getPhotoInlineDimensions(photo: ApiPhoto): IDimensions | undefined {
  return (
    photo.sizes.find((size) => size.type === 'x')
    || photo.sizes.find((size) => size.type === 'm')
    || photo.sizes.find((size) => size.type === 's')
    || photo.thumbnail
  );
}

export function getVideoDimensions(video: ApiVideo): IDimensions | undefined {
  if (video.width && video.height) {
    return video as IDimensions;
  }

  return undefined;
}

export function getMediaTransferState(message: ApiMessage, progress?: number, isDownloadNeeded = false) {
  const isUploading = isMessageLocal(message);
  const isTransferring = isUploading || isDownloadNeeded;
  const transferProgress = Number(progress);

  return {
    isUploading, isTransferring, transferProgress,
  };
}

export function getMessageContentIds(
  messages: Record<number, ApiMessage>, messageIds: number[], contentType: ApiMessageSearchType,
) {
  let validator: Function;

  switch (contentType) {
    case 'media':
      validator = (message: ApiMessage) => {
        const video = getMessageVideo(message);
        return getMessagePhoto(message) || (video && !video.isRound && !video.isGif);
      };
      break;

    case 'documents':
      validator = getMessageDocument;
      break;

    case 'links':
      validator = (message: ApiMessage) => getMessageWebPage(message) || matchLinkInMessageText(message);
      break;

    case 'audio':
      validator = getMessageAudio;
      break;

    default:
      return [] as Array<number>;
  }

  return messageIds.reduce((result, messageId) => {
    if (messages[messageId] && validator(messages[messageId])) {
      result.push(messageId);
    }

    return result;
  }, [] as Array<number>);
}

export function getMediaDuration(message: ApiMessage) {
  const { audio, voice, video } = getMessageContent(message);
  const media = audio || voice || video || getMessageWebPageVideo(message);
  if (!media) {
    return undefined;
  }

  return media.duration;
}
