package com.bytesw.bytebot.etl.services;

import com.bytesw.bytebot.etl.batch.beans.DeleteDataSensBean;
import com.bytesw.bytebot.etl.beans.SessionBean;
import com.bytesw.bytebot.etl.dao.IntentRepository;
import com.bytesw.bytebot.etl.dao.MessageRepository;
import com.bytesw.bytebot.etl.dao.UserRepository;
import com.bytesw.bytebot.etl.enums.MessageTypeEnum;
import com.bytesw.bytebot.etl.jdbc.ETLMessageJDBCRepository;
import com.bytesw.bytebot.etl.jdbc.ETLSessionBotJDBCRepository;
import com.bytesw.bytebot.etl.model.Intent;
import com.bytesw.bytebot.etl.model.Message;
import com.bytesw.bytebot.etl.model.Session;
import com.bytesw.bytebot.etl.model.User;
import com.bytesw.bytebot.etl.utils.JsonUtils;
import com.bytesw.bytebot.jdbc.DeleteDataSensJDBCRepository;
import com.bytesw.bytebot.model.Channel;
import com.bytesw.bytebot.model.enums.AgentParameterEnum;
import com.bytesw.bytebot.model.enums.AgentStatusEnum;
import com.bytesw.bytebot.repository.ChannelRepository;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Log4j2
@Service
@Transactional
public class UserMessageProcessed extends MessageProcessedSupport implements MessageProcessed {

    @Autowired
    private ETLSessionBotJDBCRepository sessionBotJDBCRepository;

    @Autowired
    private ETLMessageJDBCRepository messageJDBCRepository;

    @Autowired
    private ChannelRepository chanelRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private MessageRepository messageRepository;

    @Autowired
    private IntentRepository intentRepository;

    @Autowired
    private DeleteDataSensJDBCRepository deleteDataSensJDBCRepository;

    @Value("${application.etl.text-user.threshold:0.5}")
    private BigDecimal threshold;

    @PostConstruct
    private void init() {
        this.fields.put(SENDER_ID_FIELD_NAME, "$.sender_id");
        this.fields.put(CONFIDENCE_FIELD_NAME, "$.parse_data.intent.confidence");
        this.fields.put(CONTENT_FIELD_NAME, "$.text");
        this.fields.put(CHANNEL_FIELD_NAME, "$.input_channel");
        this.fields.put(TIMESTAMP_FIELD_NAME, "$.timestamp");
        this.fields.put(INTENT_NAME, "$.parse_data.intent.name");
    }

    @Override
    public boolean process(String json, String oldSenderId) {
        String senderId = oldSenderId != null ? oldSenderId : (String) JsonUtils.getFieldFromJson(json, this.fields.get(SENDER_ID_FIELD_NAME));
        if (senderId != null) {
            Optional<User> userFound = userRepository.findByIdentifier(senderId);
            if (!userFound.isPresent()) {
                return false;
            }
            SessionBean session = sessionBotJDBCRepository.getLastSessionByUser(userFound.get().getId());
            if (session != null) {
                /* ID del agente */
                Long agentId = identifierAgent(json);
                if (agentId >= 1) {
                    Message message = cloneMessage(json, session.getId(), agentId);
                    if (message != null) {
                        int correlative = messageJDBCRepository.getLastCorrelativeBySession(message.getSessionId());
                        correlative++;
                        message.setCorrelative(correlative);

                        messageRepository.save(message);

                        String channel = (String) JsonUtils.getFieldFromJson(json, this.fields.get(CHANNEL_FIELD_NAME));

                        updateSession(session.getId(), message.getDate(), channel);
                        return true;
                    }
                }
            }
        }
        return false;
    }

    private void updateSession(Long sessionId, OffsetDateTime date, String channelIdentifier) {
        Optional<Session> sessionFond = sessionBotRepository.findById(sessionId);
        if (sessionFond.isPresent()) {
            Session session = sessionFond.get();
            session.setLastEventDate(date);
            if (channelIdentifier != null && session.getChannel() == null) {
                Optional<Channel> channelFound = chanelRepository.findByName(channelIdentifier);
                if (channelFound.isPresent()) {
                    session.setChannel(channelFound.get());
                }
            }
            sessionBotRepository.save(session);
        }
    }

    private Message cloneMessage(String json, Long sessionId, Long agentId) {
        Double timestamp = (Double) JsonUtils.getFieldFromJson(json, this.fields.get(TIMESTAMP_FIELD_NAME));
        Object confidence = JsonUtils.getFieldFromJson(json, this.fields.get(CONFIDENCE_FIELD_NAME));
        String content = (String) JsonUtils.getFieldFromJson(json, this.fields.get(CONTENT_FIELD_NAME));
        OffsetDateTime messageDate = getOffsetDateTimeFromTimestampPython(timestamp);

        BigDecimal probability = null;
        if (confidence instanceof Double) {
            probability = new BigDecimal((Double) confidence);
        } else if (confidence instanceof BigDecimal) {
            probability = (BigDecimal) confidence;
        }


        if (messageDate == null || probability == null) {
            return null;
        }

        Message message = Message.builder()
                .content(content)
                .sessionId(sessionId)
                .date(messageDate)
                .probability(new BigDecimal(String.valueOf(probability)))
                .type((probability.compareTo(threshold) >= 0) ? MessageTypeEnum.ACCEPTED : MessageTypeEnum.REJECTED)
                //.correlative()
                .build();

        if (MessageTypeEnum.ACCEPTED.equals(message.getType())) {
            String intentName = (String) JsonUtils.getFieldFromJson(json, this.fields.get(INTENT_NAME));
            Optional<Intent> optionalIntent = intentRepository.findIntenNameById(intentName, agentId);
            if (optionalIntent.isPresent()) {
                message.setIntentId(optionalIntent.get().getId());
            }
        }
        return message;
    }

    //-------
    private Long identifierAgent(String json){
        Long agentId = 0l;
        String number= (String) JsonUtils.getFieldFromJson(json, "$.metadata.To");
        if (number != null) {
            number = number.split(":")[1];
            List<DeleteDataSensBean> deleteDataSensBeans = deleteDataSensJDBCRepository
                    .getListAgentChannel(AgentStatusEnum.DEPLOYED.getName(), AgentParameterEnum.ACCESS_TWILIO.getName());
            for (DeleteDataSensBean deleteDataSensBean: deleteDataSensBeans) {
                Object numeros = JsonUtils.getFieldFromJson(deleteDataSensBean.getChannelValue(), "$.telefono_despliegue");
                List<String> numerosAgentes = numbersAgent((List<Map>) numeros);
                if (numerosAgentes.contains(number)) {
                    agentId = deleteDataSensBean.getAgenId();
                    break;
                }
            }
        }
        return agentId;
    }

    private List<String> numbersAgent(List<Map> listNumber){
        List<String> result = new ArrayList<>();
        for (Map map : listNumber){
            String cod = (String) map.get("codigoInternacional");
            String number = (String) map.get("numero");
            String agent = "+" + cod + number;
            result.add(agent);
        }
        return result;
    }
    //------

}
