/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.

For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "ui/chat/attach/attach_single_media_preview.h"

#include "editor/photo_editor_common.h"
#include "ui/chat/attach/attach_prepare.h"
#include "core/mime_type.h"
#include "lottie/lottie_single_player.h"

namespace Ui {

SingleMediaPreview *SingleMediaPreview::Create(
		QWidget *parent,
		const style::ComposeControls &st,
		Fn<bool()> gifPaused,
		const PreparedFile &file,
		AttachControls::Type type) {
	auto preview = QImage();
	auto animated = false;
	auto animationPreview = false;
	auto hasModifications = false;
	if (const auto image = std::get_if<PreparedFileInformation::Image>(
			&file.information->media)) {
		preview = Editor::ImageModified(image->data, image->modifications);
		animated = animationPreview = image->animated;
		hasModifications = !image->modifications.empty();
	} else if (const auto video = std::get_if<PreparedFileInformation::Video>(
			&file.information->media)) {
		preview = file.videoCover
			? file.videoCover->preview
			: video->thumbnail;
		animated = true;
		animationPreview = video->isGifv;
	}
	if (preview.isNull()) {
		return nullptr;
	} else if (!animated
		&& !ValidateThumbDimensions(preview.width(), preview.height())
		&& !hasModifications) {
		return nullptr;
	}
	const auto result = CreateChild<SingleMediaPreview>(
		parent,
		st,
		std::move(gifPaused),
		preview,
		animated,
		Core::IsMimeSticker(file.information->filemime),
		file.spoiler,
		animationPreview ? file.path : QString(),
		type);
	result->setCanShowHighQualityBadge(file.canUseHighQualityPhoto());
	return result;
}

SingleMediaPreview::SingleMediaPreview(
	QWidget *parent,
	const style::ComposeControls &st,
	Fn<bool()> gifPaused,
	QImage preview,
	bool animated,
	bool sticker,
	bool spoiler,
	const QString &animatedPreviewPath,
	AttachControls::Type type)
: AbstractSingleMediaPreview(parent, st, type)
, _gifPaused(std::move(gifPaused))
, _sticker(sticker) {
	Expects(!preview.isNull());
	setAnimated(animated);

	preparePreview(preview);
	prepareAnimatedPreview(animatedPreviewPath, animated);
	setSpoiler(spoiler);
}

bool SingleMediaPreview::supportsSpoilers() const {
	return !_sticker || sendWay().sendImagesAsPhotos();
}

bool SingleMediaPreview::drawBackground() const {
	return !_sticker;
}

bool SingleMediaPreview::tryPaintAnimation(QPainter &p) {
	if (_gifPreview && _gifPreview->started()) {
		const auto paused = _gifPaused();
		const auto frame = _gifPreview->current({
			.frame = QSize(previewWidth(), previewHeight()),
		}, paused ? 0 : crl::now());
		p.drawImage(previewLeft(), previewTop(), frame);
		return true;
	} else if (_lottiePreview && _lottiePreview->ready()) {
		const auto frame = _lottiePreview->frame();
		const auto size = frame.size() / style::DevicePixelRatio();
		p.drawImage(
			QRect(
				previewLeft() + (previewWidth() - size.width()) / 2,
				(previewHeight() - size.height()) / 2,
				size.width(),
				size.height()),
			frame);
		_lottiePreview->markFrameShown();
		return true;
	}
	return false;
}

bool SingleMediaPreview::isAnimatedPreviewReady() const {
	return _gifPreview || _lottiePreview;
}

void SingleMediaPreview::prepareAnimatedPreview(
		const QString &animatedPreviewPath,
		bool animated) {
	if (_sticker && animated) {
		const auto box = QSize(previewWidth(), previewHeight())
			* style::DevicePixelRatio();
		_lottiePreview = std::make_unique<Lottie::SinglePlayer>(
			Lottie::ReadContent(QByteArray(), animatedPreviewPath),
			Lottie::FrameRequest{ box });
		_lottiePreview->updates(
		) | rpl::on_next([=] {
			update();
		}, lifetime());
	} else if (!animatedPreviewPath.isEmpty()) {
		auto callback = [=](Media::Clip::Notification notification) {
			clipCallback(notification);
		};
		_gifPreview = Media::Clip::MakeReader(
			animatedPreviewPath,
			std::move(callback));
	}
}

void SingleMediaPreview::clipCallback(
		Media::Clip::Notification notification) {
	using namespace Media::Clip;
	switch (notification) {
	case Notification::Reinit: {
		if (_gifPreview && _gifPreview->state() == State::Error) {
			_gifPreview.setBad();
		}

		if (_gifPreview && _gifPreview->ready() && !_gifPreview->started()) {
			_gifPreview->start({
				.frame = QSize(previewWidth(), previewHeight()),
			});
		}

		update();
	} break;

	case Notification::Repaint: {
		if (_gifPreview && !_gifPreview->currentDisplayed()) {
			update();
		}
	} break;
	}
}

} // namespace Ui
