/*
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 "api/api_editing.h"

#include "apiwrap.h"
#include "api/api_media.h"
#include "api/api_text_entities.h"
#include "boxes/confirm_box.h"
#include "data/data_scheduled_messages.h"
#include "data/data_session.h"
#include "history/history.h"
#include "history/history_item.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "mtproto/mtproto_rpc_sender.h"

namespace Api {
namespace {

mtpRequestId EditMessage(
		not_null<HistoryItem*> item,
		const TextWithEntities &textWithEntities,
		SendOptions options,
		Fn<void(const MTPUpdates &, Fn<void()>)> done,
		Fn<void(const RPCError &)> fail,
		std::optional<MTPInputMedia> inputMedia = std::nullopt) {
	const auto session = &item->history()->session();
	const auto api = &session->api();

	const auto text = textWithEntities.text;
	const auto sentEntities = EntitiesToMTP(
		session,
		textWithEntities.entities,
		ConvertOption::SkipLocal);
	const auto media = item->media();

	const auto emptyFlag = MTPmessages_EditMessage::Flag(0);
	const auto flags = emptyFlag
	| (!text.isEmpty() || media
		? MTPmessages_EditMessage::Flag::f_message
		: emptyFlag)
	| ((media && inputMedia.has_value())
		? MTPmessages_EditMessage::Flag::f_media
		: emptyFlag)
	| ((!media || !media->webpage())
		? MTPmessages_EditMessage::Flag::f_no_webpage
		: emptyFlag)
	| (!sentEntities.v.isEmpty()
		? MTPmessages_EditMessage::Flag::f_entities
		: emptyFlag)
	| (options.scheduled
		? MTPmessages_EditMessage::Flag::f_schedule_date
		: emptyFlag);

	const auto id = item->isScheduled()
		? session->data().scheduledMessages().lookupId(item)
		: item->id;
	return api->request(MTPmessages_EditMessage(
		MTP_flags(flags),
		item->history()->peer->input,
		MTP_int(id),
		MTP_string(text),
		inputMedia.value_or(MTPInputMedia()),
		MTPReplyMarkup(),
		sentEntities,
		MTP_int(options.scheduled)
	)).done([=](const MTPUpdates &result) {
		done(result, [=] { api->applyUpdates(result); });
	}).fail(
		fail
	).send();
}

mtpRequestId EditMessage(
		not_null<HistoryItem*> item,
		SendOptions options,
		Fn<void(const MTPUpdates &, Fn<void()>)> done,
		Fn<void(const RPCError &)> fail,
		std::optional<MTPInputMedia> inputMedia = std::nullopt) {
	const auto &text = item->originalText();
	return EditMessage(item, text, options, done, fail, inputMedia);
}

void EditMessageWithUploadedMedia(
		not_null<HistoryItem*> item,
		SendOptions options,
		MTPInputMedia media) {
	const auto done = [=](const auto &result, Fn<void()> applyUpdates) {
		if (item) {
			item->clearSavedMedia();
			item->setIsLocalUpdateMedia(true);
			applyUpdates();
			item->setIsLocalUpdateMedia(false);
		}
	};
	const auto fail = [=](const RPCError &error) {
		const auto err = error.type();
		const auto session = &item->history()->session();
		const auto notModified = (err == u"MESSAGE_NOT_MODIFIED"_q);
		const auto mediaInvalid = (err == u"MEDIA_NEW_INVALID"_q);
		if (notModified || mediaInvalid) {
			item->returnSavedMedia();
			session->data().sendHistoryChangeNotifications();
			if (mediaInvalid) {
				Ui::show(
					Box<InformBox>(tr::lng_edit_media_invalid_file(tr::now)),
					Ui::LayerOption::KeepOther);
			}
		} else {
			session->api().sendMessageFail(error, item->history()->peer);
		}
	};

	EditMessage(item, options, done, fail, media);
}

} // namespace

void RescheduleMessage(
		not_null<HistoryItem*> item,
		SendOptions options) {
	const auto done = [=](const auto &result, Fn<void()> applyUpdates) {
		applyUpdates();
	};
	const auto fail = [](const RPCError &error) {};

	EditMessage(item, options, done, fail);
}

void EditMessageWithUploadedDocument(
		HistoryItem *item,
		const MTPInputFile &file,
		const std::optional<MTPInputFile> &thumb,
		SendOptions options) {
	if (!item || !item->media() || !item->media()->document()) {
		return;
	}
	const auto media = PrepareUploadedDocument(item, file, thumb);
	EditMessageWithUploadedMedia(item, options, media);
}

void EditMessageWithUploadedPhoto(
		HistoryItem *item,
		const MTPInputFile &file,
		SendOptions options) {
	if (!item || !item->media() || !item->media()->photo()) {
		return;
	}
	const auto media = PrepareUploadedPhoto(file);
	EditMessageWithUploadedMedia(item, options, media);
}

mtpRequestId EditCaption(
		not_null<HistoryItem*> item,
		const TextWithEntities &caption,
		Fn<void(const MTPUpdates &)> done,
		Fn<void(const RPCError &)> fail) {
	const auto callback = [=](const auto &result, Fn<void()> applyUpdates) {
		done(result);
		applyUpdates();
	};
	return EditMessage(item, caption, SendOptions(), callback, fail);
}


} // namespace Api