package ru.kayashov.bar.bot.config;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.methods.updatingmessages.DeleteMessage;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.api.objects.User;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboard;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import ru.kayashov.bar.bot.domain.Bot;
import ru.kayashov.bar.bot.domain.command.CommandContainer;
import ru.kayashov.bar.bot.domain.command.api.Command;
import ru.kayashov.bar.bot.domain.methods.AbstractDeleteMessage;
import ru.kayashov.bar.bot.domain.methods.AbstractInlineKeyboard;
import ru.kayashov.bar.bot.domain.methods.AbstractMethod;
import ru.kayashov.bar.bot.domain.methods.AbstractSendKeyboardMessage;
import ru.kayashov.bar.bot.domain.methods.AbstractSendMessage;
import ru.kayashov.bar.bot.domain.model.AbstractUpdate;

import java.util.List;

@Slf4j
@Component
@RequiredArgsConstructor
public class TelegramExecutorBot extends TelegramLongPollingBot implements Bot {

    private final TelegramBotMapper mapper;
    private final TelegramBotProperty botConfig;
    private final CommandContainer commandContainer;

    @Override
    public String getBotUsername() {
        return botConfig.getUsername();
    }

    @Override
    public String getBotToken() {
        return botConfig.getBotToken();
    }

    @Override
    public void onUpdateReceived(Update update) {
        if (update.hasMessage()) {
            Message reply = update.getMessage().getReplyToMessage();
            if (reply != null) {
                String text = update.getMessage().getText();
                String data = "Cocktail:jump:" + text + ":" + reply.getMessageId();
                AbstractUpdate message = mapper.toAbstractUpdate(update);
                message.getMessage().setMessage(data);
                methodExecute(commandContainer.retrieveCommand("Cocktail").execute(message));
                return;
            }
            if (update.hasMessage()) {
                String data = update.getMessage().getText();
                int dot = data.indexOf(':');
                if (dot > -1) {
                    data = data.substring(0, data.indexOf(":"));
                }
                methodExecute(commandContainer
                        .retrieveCommand(data)
                        .execute(mapper.toAbstractUpdate(update)));
            }
        } else if (update.hasCallbackQuery() && !update.getCallbackQuery().getData().equals("null")) {
            String callbackData = update.getCallbackQuery().getData();
            String callbackCommand = callbackData.substring(0, callbackData.indexOf(":"));/*.replace("{\"", "");*/
            Command command = commandContainer.retrieveCommand(callbackCommand);
            List<? extends AbstractMethod> methods = command.execute(mapper.toAbstractUpdate(update));
            methodExecute(methods);
        }
    }

    @Override
    public void sendMessage(AbstractSendMessage message) {
        SendMessage sendMessage = SendMessage.builder()
                .chatId(message.getChatId())
                .text(message.getMessage())
                .parseMode("HTML")
                .build();
        try {
            execute(sendMessage);
            log.info("AbstractMessage successfully sent to chat with id {}", message.getChatId());
        } catch (TelegramApiException e) {
            log.error("AbstractMessage {} didn't send to chat with id {}", message, message.getChatId(), e);
        }
    }

    @Override
    public void sendKeyboardMessage(AbstractSendKeyboardMessage message) {
        send(getMessage(message.getChatId(), message.getMessage(), mapper.toReplyKeyboard(message.getKeyboard())));
    }

    @Override
    public void sendInlineKeyboard(AbstractInlineKeyboard message) {
        send(getMessage(message.getChatId(), message.getMessage(), mapper.toInlineKeyboard(message.getKeyboard())));
    }

    @Override
    public void deleteMessage(AbstractDeleteMessage message) {
        delete(getDeleteMessage(message.getChatId(), message.getMessageId()));
    }

    private SendMessage getMessage(Long chatId, String message, ReplyKeyboard replyKeyboard) {
        return SendMessage.builder()
                .chatId(chatId)
                .text(message)
                .parseMode("HTML")
                .replyMarkup(replyKeyboard)
                .build();
    }

    private DeleteMessage getDeleteMessage(Long chatId, Integer messageId) {
        return DeleteMessage.builder()
                .chatId(chatId)
                .messageId(messageId)
                .build();
    }

    private void delete(DeleteMessage abstractDeleteMessage) {
        try {
            execute(abstractDeleteMessage);
        } catch (TelegramApiException e) {
            e.printStackTrace();
        }
    }

    private void send(SendMessage sendMessage) {
        try {
            execute(sendMessage);
            log.info("AbstractMessage {} successfully sent to chat with id {}", sendMessage.getText(), sendMessage.getChatId());
        } catch (TelegramApiException e) {
            log.error("AbstractMessage {} didn't send to chat with id {}", sendMessage.getText(), sendMessage.getChatId(), e);
        }
    }
}
