package com.cameleer.server.app.controller;

import com.cameleer.common.model.AgentEvent;
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.RouteStateRegistry;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

/**
 * Ingestion endpoint for agent lifecycle events.
 * <p>
 * Agents emit events (AGENT_STARTED, AGENT_STOPPED, etc.) which are
 * stored in the event log. AGENT_STOPPED triggers a graceful shutdown
 * transition in the registry.
 */
@RestController
@RequestMapping("/api/v1/data")
@Tag(name = "Ingestion", description = "Data ingestion endpoints")
public class EventIngestionController {

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

    private final AgentEventService agentEventService;
    private final AgentRegistryService registryService;
    private final ObjectMapper objectMapper;
    private final RouteStateRegistry routeStateRegistry;

    public EventIngestionController(AgentEventService agentEventService,
                                     AgentRegistryService registryService,
                                     ObjectMapper objectMapper,
                                     RouteStateRegistry routeStateRegistry) {
        this.agentEventService = agentEventService;
        this.registryService = registryService;
        this.objectMapper = objectMapper;
        this.routeStateRegistry = routeStateRegistry;
    }

    @PostMapping("/events")
    @Operation(summary = "Ingest agent events")
    public ResponseEntity<Void> ingestEvents(@RequestBody String body) {
        String instanceId = extractInstanceId();

        List<AgentEvent> events;
        try {
            String trimmed = body.strip();
            if (trimmed.startsWith("[")) {
                events = objectMapper.readValue(trimmed, new TypeReference<List<AgentEvent>>() {});
            } else {
                events = List.of(objectMapper.readValue(trimmed, AgentEvent.class));
            }
        } catch (Exception e) {
            log.warn("Failed to parse event payload: {}", e.getMessage());
            return ResponseEntity.badRequest().build();
        }

        AgentInfo agent = registryService.findById(instanceId);
        String applicationId = agent != null ? agent.applicationId() : "";
        String environment = agent != null ? agent.environmentId() : null;

        for (AgentEvent event : events) {
            agentEventService.recordEvent(instanceId, applicationId, environment,
                    event.getEventType(),
                    event.getDetails() != null ? event.getDetails().toString() : null);

            if ("AGENT_STOPPED".equals(event.getEventType())) {
                log.info("Agent {} reported graceful shutdown", instanceId);
                registryService.shutdown(instanceId);
            }

            if ("ROUTE_STATE_CHANGED".equals(event.getEventType())) {
                Map<String, String> details = event.getDetails();
                if (details != null) {
                    String routeId = details.get("routeId");
                    String newState = details.get("newState");
                    if (routeId != null && newState != null) {
                        RouteStateRegistry.RouteState state = parseRouteState(newState);
                        if (state != null) {
                            routeStateRegistry.setState(applicationId, routeId, state);
                            log.debug("Route state changed: {}/{} -> {} (reason: {})",
                                applicationId, routeId, newState, details.get("reason"));
                        }
                    }
                }
            }
        }

        return ResponseEntity.accepted().build();
    }

    private RouteStateRegistry.RouteState parseRouteState(String state) {
        if (state == null) return null;
        return switch (state) {
            case "Started" -> RouteStateRegistry.RouteState.STARTED;
            case "Stopped" -> RouteStateRegistry.RouteState.STOPPED;
            case "Suspended" -> RouteStateRegistry.RouteState.SUSPENDED;
            default -> null;
        };
    }

    private String extractInstanceId() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        return auth != null ? auth.getName() : "";
    }
}
