package com.cameleer.server.app.controller;

import com.cameleer.common.graph.RouteGraph;
import com.cameleer.server.app.web.EnvPath;
import com.cameleer.server.core.diagram.DiagramLayout;
import com.cameleer.server.core.diagram.DiagramRenderer;
import com.cameleer.server.core.runtime.Environment;
import com.cameleer.server.core.storage.DiagramStore;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Optional;

/**
 * Diagram rendering and lookup.
 * <p>
 * Content-addressed rendering stays flat at /api/v1/diagrams/{contentHash}/render:
 * the hash is globally unique, permalinks are valuable, and no env partitioning
 * is possible or needed.
 * <p>
 * By-app-and-route lookup is env-scoped at
 * /api/v1/environments/{envSlug}/apps/{appSlug}/routes/{routeId}/diagram.
 */
@RestController
@Tag(name = "Diagrams", description = "Diagram rendering endpoints")
public class DiagramRenderController {

    private static final MediaType SVG_MEDIA_TYPE = MediaType.valueOf("image/svg+xml");

    private final DiagramStore diagramStore;
    private final DiagramRenderer diagramRenderer;

    public DiagramRenderController(DiagramStore diagramStore,
                                    DiagramRenderer diagramRenderer) {
        this.diagramStore = diagramStore;
        this.diagramRenderer = diagramRenderer;
    }

    @GetMapping("/api/v1/diagrams/{contentHash}/render")
    @Operation(summary = "Render a route diagram by content hash",
            description = "Returns SVG (default) or JSON layout based on Accept header. "
                    + "Content hashes are globally unique, so this endpoint is intentionally flat (no env).")
    @ApiResponse(responseCode = "200", description = "Diagram rendered successfully",
            content = {
                    @Content(mediaType = "image/svg+xml", schema = @Schema(type = "string")),
                    @Content(mediaType = "application/json", schema = @Schema(implementation = DiagramLayout.class))
            })
    @ApiResponse(responseCode = "404", description = "Diagram not found")
    public ResponseEntity<?> renderDiagram(
            @PathVariable String contentHash,
            @RequestParam(defaultValue = "LR") String direction,
            HttpServletRequest request) {

        Optional<RouteGraph> graphOpt = diagramStore.findByContentHash(contentHash);
        if (graphOpt.isEmpty()) {
            return ResponseEntity.notFound().build();
        }

        RouteGraph graph = graphOpt.get();
        String accept = request.getHeader("Accept");

        if (accept != null && isJsonPreferred(accept)) {
            DiagramLayout layout = diagramRenderer.layoutJson(graph, direction);
            return ResponseEntity.ok()
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(layout);
        }

        String svg = diagramRenderer.renderSvg(graph);
        return ResponseEntity.ok()
                .contentType(SVG_MEDIA_TYPE)
                .body(svg);
    }

    @GetMapping("/api/v1/environments/{envSlug}/apps/{appSlug}/routes/{routeId}/diagram")
    @Operation(summary = "Find the latest diagram for this app's route in this environment",
            description = "Returns the most recently stored diagram for (app, env, route). Independent of the "
                    + "agent registry, so routes removed from the current app version still resolve.")
    @ApiResponse(responseCode = "200", description = "Diagram layout returned")
    @ApiResponse(responseCode = "404", description = "No diagram found")
    public ResponseEntity<DiagramLayout> findByAppAndRoute(
            @EnvPath Environment env,
            @PathVariable String appSlug,
            @PathVariable String routeId,
            @RequestParam(defaultValue = "LR") String direction) {
        Optional<String> contentHash = diagramStore.findLatestContentHashForAppRoute(appSlug, routeId, env.slug());
        if (contentHash.isEmpty()) {
            return ResponseEntity.notFound().build();
        }

        Optional<RouteGraph> graphOpt = diagramStore.findByContentHash(contentHash.get());
        if (graphOpt.isEmpty()) {
            return ResponseEntity.notFound().build();
        }

        DiagramLayout layout = diagramRenderer.layoutJson(graphOpt.get(), direction);
        return ResponseEntity.ok(layout);
    }

    private boolean isJsonPreferred(String accept) {
        String[] parts = accept.split(",");
        if (parts.length == 0) return false;
        String first = parts[0].trim().split(";")[0].trim();
        return "application/json".equalsIgnoreCase(first);
    }
}
