package com.cameleer.server.app.controller;

import com.cameleer.server.app.dto.LogEntryResponse;
import com.cameleer.server.app.dto.LogSearchPageResponse;
import com.cameleer.server.app.web.EnvPath;
import com.cameleer.server.core.runtime.Environment;
import com.cameleer.server.core.search.LogSearchRequest;
import com.cameleer.server.core.search.LogSearchResponse;
import com.cameleer.server.core.storage.LogIndex;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.Instant;
import java.util.Arrays;
import java.util.List;

@RestController
@RequestMapping("/api/v1/environments/{envSlug}")
@Tag(name = "Application Logs", description = "Query application logs (env-scoped)")
public class LogQueryController {

    private final LogIndex logIndex;

    public LogQueryController(LogIndex logIndex) {
        this.logIndex = logIndex;
    }

    @GetMapping("/logs")
    @Operation(summary = "Search application log entries in this environment",
            description = "Cursor-paginated log search scoped to the env in the path. "
                    + "Supports free-text search, multi-level filtering, and optional application/agent scoping.")
    public ResponseEntity<LogSearchPageResponse> searchLogs(
            @EnvPath Environment env,
            @RequestParam(required = false) String q,
            @RequestParam(required = false) String query,
            @RequestParam(required = false) String level,
            @RequestParam(required = false) String application,
            @RequestParam(name = "agentId", required = false) String instanceId,
            @RequestParam(required = false) String exchangeId,
            @RequestParam(required = false) String logger,
            @RequestParam(required = false) String source,
            @RequestParam(required = false) String instanceIds,
            @RequestParam(required = false) String from,
            @RequestParam(required = false) String to,
            @RequestParam(required = false) String cursor,
            @RequestParam(defaultValue = "100") int limit,
            @RequestParam(defaultValue = "desc") String sort) {

        // q takes precedence over deprecated query param
        String searchText = q != null ? q : query;

        List<String> levels = List.of();
        if (level != null && !level.isEmpty()) {
            levels = Arrays.stream(level.split(","))
                    .map(String::trim)
                    .filter(s -> !s.isEmpty())
                    .toList();
        }

        List<String> sources = List.of();
        if (source != null && !source.isEmpty()) {
            sources = Arrays.stream(source.split(","))
                    .map(String::trim)
                    .filter(s -> !s.isEmpty())
                    .toList();
        }

        List<String> instanceIdList = List.of();
        if (instanceIds != null && !instanceIds.isEmpty()) {
            instanceIdList = Arrays.stream(instanceIds.split(","))
                    .map(String::trim)
                    .filter(s -> !s.isEmpty())
                    .toList();
        }

        Instant fromInstant = from != null ? Instant.parse(from) : null;
        Instant toInstant = to != null ? Instant.parse(to) : null;

        LogSearchRequest request = new LogSearchRequest(
                searchText, levels, application, instanceId, exchangeId,
                logger, env.slug(), sources, fromInstant, toInstant, cursor, limit, sort,
                instanceIdList);

        LogSearchResponse result = logIndex.search(request);

        List<LogEntryResponse> entries = result.data().stream()
                .map(r -> new LogEntryResponse(
                        r.timestamp(), r.level(), r.loggerName(),
                        r.message(), r.threadName(), r.stackTrace(),
                        r.exchangeId(), r.instanceId(), r.application(),
                        r.mdc(), r.source()))
                .toList();

        return ResponseEntity.ok(new LogSearchPageResponse(
                entries, result.nextCursor(), result.hasMore(), result.levelCounts()));
    }
}
