package com.bytesw.bytebot.service;


import com.bytesw.bytebot.etl.beans.GoalBean;
import com.bytesw.bytebot.etl.model.Goal;
import com.bytesw.bytebot.repository.*;
import com.bytesw.xdf.exception.AlreadyExistsException;
import com.bytesw.xdf.exception.NotFoundException;
import com.bytesw.xdf.service.XDFService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
@Transactional
@Log4j2
public class GoalService extends XDFService<Goal, Map, Long> {

    @Autowired
    private GoalRepository goalRepository;

    @Autowired
    private GoalForActionsRepository goalForActionsRepository;

    @Autowired
    private AgentRepository agentRepository;

    @Autowired
    private GoalForActionService goalForActionService;

    protected GoalService(GoalRepository repository) {
        super(repository);
    }

    @Override
    protected Goal toModel(Goal model, Map map) {
        if (model == null) {
            model = new Goal();
        }
        model.setId((Long) map.get("id"));
        model.setIdentifier(String.valueOf(map.get("identifier")));
        model.setAgenId((Long) map.get("agentId"));
        return model;
    }

    @Override
    protected Map toBean(Goal model) {
        Map<String, Object> map = new HashMap<>();
        map.put("id",model.getId());
        map.put("identifier", model.getIdentifier());
        map.put("agentId", model.getAgenId());
        return map;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Map create(Map body) {

        Goal goal = new Goal();

        if (body.isEmpty()) {
            throw new NotFoundException("No se encuentran parametros.");
        }

        List<Object> actions = (List) body.get("actionList");
        if (actions.isEmpty()) {
            throw new NotFoundException("Debe poseer minimo un action.");
        }

        Long agenId = Long.valueOf(body.get("agentId").toString());

        if (!agentRepository.existsById(agenId)) {
            throw new NotFoundException("Agente no registrado.");
        }

        String ident = body.get("identifier").toString();
        Optional<Goal> goalOptional= goalRepository.findByAgentAndIdent(agenId, ident);

        if (goalOptional.isPresent()) {
            throw new AlreadyExistsException("Goal ya existe en la base de datos.");
        }

        goal.setAgenId(agenId);
        goal.setIdentifier(ident);
        goal = goalRepository.save(goal);
        goalForActionService.saveGoalForAction(goal.getId(), actions);
        return toBean(goal);

    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void delete(Long goalId) {
        if (!goalRepository.existsById(goalId)){
            throw new NotFoundException("Goal no registrado.");
        }
        goalForActionService.deleteGoalForAction(goalId);
        goalRepository.deleteById(goalId);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Map update(Map body, Long goalId) {

        if (body.isEmpty()) {
            throw new NotFoundException("No se encuentran parametros.");
        }

        if (!goalRepository.existsById(goalId)) {
            throw new NotFoundException("Goal no se encuenta registrado");
        }

        List<Object> actions = (List) body.get("actionList");
        if (actions.isEmpty()) {
            throw new NotFoundException("Debe poseer minimo un action.");
        }

        Long agenId = Long.valueOf(body.get("agentId").toString());
        String ident = body.get("identifier").toString();

        if (!agentRepository.existsById(agenId)) {
            throw new NotFoundException("Agente no registrado.");
        }

        Optional<Goal> goalOptional= goalRepository.findByAgentAndIdent(agenId, ident);

        if (goalOptional.isPresent()) {
            if (goalOptional.get().getId() != goalId) {
                throw new AlreadyExistsException("Goal ya existe en la base de datos para el agente ingresado.");
            }
        }

        Goal goal = new Goal();
        goal.setId(goalId);
        goal.setAgenId(agenId);
        goal.setIdentifier(ident);

        goal = goalRepository.save(goal);
        goalForActionService.updateGoalForAction(goal.getId(), actions);

        return toBean(goal);
    }

    @Override
    public Map getById(Long id){
        Map<String, Object> result = new HashMap<>();
        Optional<Goal> goal = goalRepository.findById(id);

        if (!goal.isPresent()) {
            throw new NotFoundException("Goal no se encuenta registrado");
        }

        List<Map> listAction = goalForActionService.getGoalForAction(id);
        if (listAction.isEmpty()) {
            throw new NotFoundException("Actions no encontrados");
        }

        result.put("id", goal.get().getId());
        result.put("agentId", goal.get().getAgenId());
        result.put("identifier", goal.get().getIdentifier());
        result.put("actionList", listAction);
        return result;
    }

    @Override
    public List<Map> getAll(){
        List<Map> result = new ArrayList<>();
        List<Goal> list = (List<Goal>) goalRepository.findAll();
        for (Goal goal: list) {
            result.add(getById(goal.getId()));
        }
        return result;
    }

}