package com.cameleer.server.app.agent;

import com.cameleer.server.app.metrics.ServerMetrics;
import com.cameleer.server.core.agent.AgentEventService;
import com.cameleer.server.core.agent.AgentInfo;
import com.cameleer.server.core.agent.AgentRegistryService;
import com.cameleer.server.core.agent.AgentState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * Periodic task that checks agent lifecycle and expires old commands.
 * <p>
 * Runs on a configurable fixed delay (default 10 seconds). Transitions
 * agents LIVE -> STALE -> DEAD based on heartbeat timing, and removes
 * expired pending commands. Records lifecycle events for state transitions.
 */
@Component
public class AgentLifecycleMonitor {

    private static final Logger log = LoggerFactory.getLogger(AgentLifecycleMonitor.class);

    private final AgentRegistryService registryService;
    private final AgentEventService agentEventService;
    private final ServerMetrics serverMetrics;

    public AgentLifecycleMonitor(AgentRegistryService registryService,
                                  AgentEventService agentEventService,
                                  ServerMetrics serverMetrics) {
        this.registryService = registryService;
        this.agentEventService = agentEventService;
        this.serverMetrics = serverMetrics;
    }

    @Scheduled(fixedDelayString = "${agent-registry.lifecycle-check-interval-ms:10000}")
    public void checkLifecycle() {
        try {
            // Snapshot states before lifecycle check
            Map<String, AgentState> statesBefore = new HashMap<>();
            for (AgentInfo agent : registryService.findAll()) {
                statesBefore.put(agent.instanceId(), agent.state());
            }

            registryService.checkLifecycle();
            registryService.expireOldCommands();

            // Detect transitions and record events
            for (AgentInfo agent : registryService.findAll()) {
                AgentState before = statesBefore.get(agent.instanceId());
                if (before != null && before != agent.state()) {
                    String eventType = mapTransitionEvent(before, agent.state());
                    if (eventType != null) {
                        agentEventService.recordEvent(agent.instanceId(), agent.applicationId(),
                                agent.environmentId(), eventType,
                                agent.displayName() + " " + before + " -> " + agent.state());
                        serverMetrics.recordAgentTransition(eventType);
                    }
                }
            }
        } catch (Exception e) {
            log.error("Error during agent lifecycle check", e);
        }
    }

    private String mapTransitionEvent(AgentState from, AgentState to) {
        if (from == AgentState.LIVE && to == AgentState.STALE) return "WENT_STALE";
        if (from == AgentState.STALE && to == AgentState.DEAD) return "WENT_DEAD";
        if (to == AgentState.LIVE && (from == AgentState.STALE || from == AgentState.DEAD)) return "RECOVERED";
        return null;
    }
}
