package ai.decompile.analysis.controller;

import ai.decompile.analysis.model.dto.LibraryResponse;
import ai.decompile.analysis.model.dto.LibrarySymbolResponse;
import ai.decompile.analysis.service.LibraryService;
import ai.decompile.analysis.service.SymbolResolutionService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

@RestController
@RequiredArgsConstructor
public class LibraryController {
  private final LibraryService libraryService;
  private final SymbolResolutionService symbolResolutionService;

  @Operation(
      summary = "Upload a library symbol dump",
      description = "Parse and store symbols from a library dump file (e.g., TurboDump output).",
      tags = {"Library Symbols"},
      operationId = "uploadLibrary")
  @PostMapping(value = "/libraries/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
  public ResponseEntity<LibraryResponse> uploadLibrary(
      @RequestPart MultipartFile file,
      @Parameter(description = "Human-readable library name, e.g. 'Borland OWL 2.52'") @RequestParam
          String name,
      @Parameter(description = "Optional description of the library")
          @RequestParam(required = false)
          String description,
      @Parameter(description = "Parser format: TURBO_DUMP") @RequestParam String parserType,
      @Parameter(
              description =
                  "Comma-separated DLL aliases, e.g. 'OWLWI,owl252.dll'. Optional — matching falls back to module name if omitted.")
          @RequestParam(required = false)
          String aliases) {
    var lib = libraryService.parseAndStore(name, description, parserType, aliases, file);
    return ResponseEntity.status(HttpStatus.CREATED).body(lib);
  }

  @Operation(
      summary = "List available parsers",
      description = "Retrieve the list of supported library symbol parser formats.",
      tags = {"Library Symbols"},
      operationId = "listParsers")
  @GetMapping("/libraries/parsers")
  public ResponseEntity<List<String>> listParsers() {
    return ResponseEntity.ok(libraryService.getAvailableParsers());
  }

  @Operation(
      summary = "List all loaded libraries",
      description = "Retrieve all library symbol databases that have been uploaded.",
      tags = {"Library Symbols"},
      operationId = "listLibraries")
  @GetMapping("/libraries")
  public ResponseEntity<List<LibraryResponse>> listLibraries() {
    return ResponseEntity.ok(libraryService.listLibraries());
  }

  @Operation(
      summary = "Get library details",
      description = "Retrieve details of a specific library symbol database.",
      tags = {"Library Symbols"},
      operationId = "getLibrary")
  @GetMapping("/libraries/{libraryId}")
  public ResponseEntity<LibraryResponse> getLibrary(@PathVariable UUID libraryId) {
    return ResponseEntity.ok(libraryService.getLibrary(libraryId));
  }

  @Operation(
      summary = "Delete a library",
      description = "Delete a library and all its associated symbols and aliases.",
      tags = {"Library Symbols"},
      operationId = "deleteLibrary")
  @DeleteMapping("/libraries/{libraryId}")
  public ResponseEntity<Void> deleteLibrary(@PathVariable UUID libraryId) {
    libraryService.deleteLibrary(libraryId);
    return ResponseEntity.noContent().build();
  }

  @Operation(
      summary = "List symbols in a library",
      description = "Retrieve paginated list of symbols within a library symbol database.",
      tags = {"Library Symbols"},
      operationId = "listLibrarySymbols")
  @GetMapping("/libraries/{libraryId}/symbols")
  public ResponseEntity<Page<LibrarySymbolResponse>> listSymbols(
      @PathVariable UUID libraryId, Pageable pageable) {
    return ResponseEntity.ok(libraryService.listSymbols(libraryId, pageable));
  }

  @Operation(
      summary = "Resolve symbols for an analysis",
      description =
          "Cross-reference imports from a specific analysis against all loaded library symbol databases.",
      tags = {"Library Symbols"},
      operationId = "resolveSymbols")
  @PostMapping("/analysis/{analysisId}/resolve-symbols")
  public ResponseEntity<Map<String, Object>> resolveSymbols(@PathVariable UUID analysisId) {
    var resolvedCount = symbolResolutionService.resolveImports(analysisId);
    return ResponseEntity.ok(Map.of("analysisId", analysisId, "resolvedCount", resolvedCount));
  }

  @Operation(
      summary = "Resolve all unresolved imports",
      description =
          "Cross-reference all unresolved imports across all analyses against all loaded library symbol databases.",
      tags = {"Library Symbols"},
      operationId = "resolveAllSymbols")
  @PostMapping("/libraries/resolve-all")
  public ResponseEntity<Map<String, Object>> resolveAllSymbols() {
    var resolvedCount = symbolResolutionService.resolveAllUnresolved();
    return ResponseEntity.ok(Map.of("resolvedCount", resolvedCount));
  }
}
