/*
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 "dialogs/ui/dialogs_video_userpic.h"

#include "core/file_location.h"
#include "data/data_peer.h"
#include "data/data_photo.h"
#include "data/data_photo_media.h"
#include "data/data_file_origin.h"
#include "data/data_session.h"
#include "dialogs/ui/dialogs_layout.h"
#include "ui/painter.h"
#include "styles/style_dialogs.h"

namespace Dialogs::Ui {

VideoUserpic::VideoUserpic(not_null<PeerData*> peer, Fn<void()> repaint)
: _peer(peer)
, _repaint(std::move(repaint)) {
}

VideoUserpic::~VideoUserpic() = default;

int VideoUserpic::frameIndex() const {
	return -1;
}

void VideoUserpic::paintLeft(
		Painter &p,
		Ui::PeerUserpicView &view,
		int x,
		int y,
		int w,
		int size,
		bool paused) {
	_lastSize = size;

	const auto photoId = _peer->userpicPhotoId();
	if (_videoPhotoId != photoId) {
		_videoPhotoId = photoId;
		_video = nullptr;
		_videoPhotoMedia = nullptr;
		const auto photo = _peer->owner().photo(photoId);
		if (photo->isNull()) {
			_peer->updateFullForced();
		} else {
			_videoPhotoMedia = photo->createMediaView();
			_videoPhotoMedia->videoWanted(
				Data::PhotoSize::Small,
				_peer->userpicPhotoOrigin());
		}
	}
	if (!_video) {
		if (!_videoPhotoMedia) {
			const auto photo = _peer->owner().photo(photoId);
			if (!photo->isNull()) {
				_videoPhotoMedia = photo->createMediaView();
				_videoPhotoMedia->videoWanted(
					Data::PhotoSize::Small,
					_peer->userpicPhotoOrigin());
			}
		}
		if (_videoPhotoMedia) {
			auto small = _videoPhotoMedia->videoContent(
				Data::PhotoSize::Small);
			auto bytes = small.isEmpty()
				? _videoPhotoMedia->videoContent(Data::PhotoSize::Large)
				: small;
			if (!bytes.isEmpty()) {
				auto callback = [=](Media::Clip::Notification notification) {
					clipCallback(notification);
				};
				_video = Media::Clip::MakeReader(
					Core::FileLocation(),
					std::move(bytes),
					std::move(callback));
			}
		}
	}
	if (rtl()) {
		x = w - x - size;
	}
	if (_video && _video->ready()) {
		startReady();

		const auto now = paused ? crl::time(0) : crl::now();
		p.drawImage(x, y, _video->current(request(size), now));
	} else {
		_peer->paintUserpicLeft(p, view, x, y, w, size);
	}
}

Media::Clip::FrameRequest VideoUserpic::request(int size) const {
	return {
		.frame = { size, size },
		.outer = { size, size },
		.factor = cIntRetinaFactor(),
		.radius = ImageRoundRadius::Ellipse,
	};
}

bool VideoUserpic::startReady(int size) {
	if (!_video->ready() || _video->started()) {
		return false;
	} else if (!_lastSize) {
		_lastSize = size ? size : _video->width();
	}
	_video->start(request(_lastSize));
	_repaint();
	return true;
}

void VideoUserpic::clipCallback(Media::Clip::Notification notification) {
	using namespace Media::Clip;

	switch (notification) {
	case Notification::Reinit: {
		if (_video->state() == State::Error) {
			_video.setBad();
		} else if (startReady()) {
			_repaint();
		}
	} break;

	case Notification::Repaint: _repaint(); break;
	}
}

void PaintUserpic(
		Painter &p,
		not_null<Entry*> entry,
		PeerData *peer,
		VideoUserpic *videoUserpic,
		PeerUserpicView &view,
		const Ui::PaintContext &context) {
	if (peer) {
		PaintUserpic(
			p,
			peer,
			videoUserpic,
			view,
			context.st->padding.left(),
			context.st->padding.top(),
			context.width,
			context.st->photoSize,
			context.paused);
	} else {
		entry->paintUserpic(p, view, context);
	}
}

void PaintUserpic(
		Painter &p,
		not_null<PeerData*> peer,
		Ui::VideoUserpic *videoUserpic,
		Ui::PeerUserpicView &view,
		int x,
		int y,
		int outerWidth,
		int size,
		bool paused) {
	if (videoUserpic) {
		videoUserpic->paintLeft(p, view, x, y, outerWidth, size, paused);
	} else {
		peer->paintUserpicLeft(p, view, x, y, outerWidth, size);
	}
}

} // namespace Dialogs::Ui
