package ua.be.wee.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import ua.be.wee.controller.PMTrigger;
import ua.be.wee.controller.rest.PTController;
import ua.be.wee.model.EnactmentController;
import ua.be.wee.model.nodes.Activity;
import ua.be.wee.model.nodes.InvokingActivity;
import ua.be.wee.model.pm.PM;
import ua.be.wee.model.pt.EndActivityEvent;
import ua.be.wee.model.pt.Event;
import ua.be.wee.model.pt.PT;
import ua.be.wee.model.pt.StartActivityEvent;
import ua.be.wee.model.repository.PTRepository;
import ua.be.wee.model.util.Pair;
import ua.be.wee.model.repository.NodeRespository;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class EnactmentService {

    // Injetando dependências necessárias
    @Autowired
    private EnactmentController controller; // Controlador para chamadas específicas, se necessário
    @Autowired
    private PTController ptController; // Outro controlador, se precisar
    @Autowired
    private PTRepository ptRepository; // Repositório para acessar dados
    @Autowired
    private NodeRespository nodeRepository; // Repositório de nós

    /** Valida os atributos da sessão */
    public boolean validateSessionAttributes(PT pt, Map<String, PM> pmMap) {
        return pt != null && pmMap != null && !pmMap.isEmpty();
    }

    /** Recupera o PM selecionado com base no branchId */
    public PM getSelectedPM(String branchId, Map<String, PM> pmMap) {
        return pmMap.get(branchId);
    }

    /** Calcula as atividades finalizadas */
    public List<Map<String, Object>> computeEndActs(List<Event> events, String branchId) {
        List<String> startedActivities = new ArrayList<>();
        List<Map<String, Object>> endActs = new ArrayList<>();
        for (Event event : events) {
            if (event instanceof StartActivityEvent) {
                StartActivityEvent startEvent = (StartActivityEvent) event;
                String activityIri = startEvent.getRelatesTo().getActivity().getIri();
                boolean ended = events.stream()
                        .filter(e -> e instanceof EndActivityEvent)
                        .map(e -> (EndActivityEvent) e)
                        .anyMatch(e -> e.getRelatesTo().getActivity().getIri().equals(activityIri));
                if (!ended) {
                    startedActivities.add(activityIri);
                    Map<String, Object> endAct = new HashMap<>();
                    endAct.put("activity", startEvent.getRelatesTo().getActivity());
                    endAct.put("branchId", branchId);
                    endActs.add(endAct);
                }
            }
        }
        return endActs;
    }

    public List<PMTrigger> computeStartActs(PT pt, PM pm, List<Event> events, String branchId, Map<String, String> invokingActivityMap) throws Exception {
        if (events.isEmpty()) {
            // MODIFICADO: Adicionado controller.getExecutionFlowManager() à chamada.
            List<Pair<String, String>> iris = controller.findNextNodes(pm.getInitial().getIri(), pt.getIri(), controller.getExecutionFlowManager());
            return findElements(pm, iris, branchId, invokingActivityMap.get(branchId));
        }
        Event lastEvent = events.get(events.size() - 1);
        if (lastEvent instanceof EndActivityEvent) {
            EndActivityEvent endEvent = (EndActivityEvent) lastEvent;
            // MODIFICADO: Adicionado controller.getExecutionFlowManager() à chamada.
            List<Pair<String, String>> iris = controller.findNextNodes(endEvent.getRelatesTo().getIri(), pt.getIri(), controller.getExecutionFlowManager());
            return findElements(pm, iris, branchId, invokingActivityMap.get(branchId));
        } else if (lastEvent instanceof StartActivityEvent) {
            StartActivityEvent startEvent = (StartActivityEvent) lastEvent;
            Activity activity = startEvent.getRelatesTo().getActivity();
            if (activity instanceof InvokingActivity) {
                InvokingActivity invokingActivity = (InvokingActivity) activity;
                PM invokedPM = controller.getPM(invokingActivity.getInvokedPM());
                // MODIFICADO: Adicionado controller.getExecutionFlowManager() à chamada.
                List<Pair<String, String>> iris = controller.findNextNodes(invokedPM.getInitial().getIri(), pt.getIri(), controller.getExecutionFlowManager());
                return findElements(invokedPM, iris, branchId, invokingActivity.getName());
            } else {
                return findStartActs(pt, branchId);
            }
        }
        return findStartActs(pt, branchId);
    }

    public List<Map<String, String>> prepareActivityList(List<PMTrigger> acts, String pmId) {
        return acts.stream()
                .filter(act -> act.getBranchId().equals(pmId))
                .map(act -> {
                    Map<String, String> activityMap = new HashMap<>();
                    activityMap.put("iri", act.getIri());
                    String name = act.getName();
                    if (act.getInvokingActivityName() != null) {
                        name += " (invocado por " + act.getInvokingActivityName() + ")";
                    }
                    activityMap.put("name", name);
                    return activityMap;
                })
                .collect(Collectors.toList());
    }

    private List<PMTrigger> findElements(PM pm, List<Pair<String, String>> iris, String branchId, String invokingActivityName) {
        return new ArrayList<>(); // Placeholder
    }

    private List<PMTrigger> findStartActs(PT trace, String branchId) throws Exception {
        // Implementação do método findStartActs aqui, se necessário
        return new ArrayList<>(); // Placeholder
    }
}