package com.ai.trackwalker.api;

import com.ai.trackwalker.model.ModelArtifactEventPublisher;
import com.ai.trackwalker.model.ModelArtifactLifecycleService;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.util.Map;

@RestController
@RequestMapping("/api/v1")
public class ModelArtifactController {
    private final ModelArtifactLifecycleService service;
    private final ModelArtifactEventPublisher events;

    public ModelArtifactController(ModelArtifactLifecycleService service, ModelArtifactEventPublisher events) {
        this.service = service;
        this.events = events;
    }

    @GetMapping("/model-artifacts/runtime-overview")
    public ApiResponse<?> runtimeOverview() {
        return ApiResponse.ok(service.runtimeOverview());
    }

    @GetMapping("/model-artifacts/{artifactId}")
    public ApiResponse<?> artifact(@PathVariable String artifactId) {
        return ApiResponse.ok(service.artifact(artifactId));
    }

    @PostMapping(value = "/model-runtime-deployments/{deploymentId}/artifacts", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ApiResponse<?> upload(
            @PathVariable String deploymentId,
            @RequestPart("primary") MultipartFile primary,
            @RequestPart(value = "secondary", required = false) MultipartFile secondary,
            @RequestPart("labels") MultipartFile labels,
            @RequestParam(required = false) String operator
    ) {
        return ApiResponse.ok(service.upload(deploymentId, primary, secondary, labels, operator));
    }

    @PostMapping("/model-runtime-deployments/{deploymentId}/installations")
    public ApiResponse<?> install(
            @PathVariable String deploymentId,
            @RequestBody(required = false) Map<String, Object> request
    ) {
        return ApiResponse.ok(service.createInstallJob(deploymentId, request == null ? Map.of() : request));
    }

    @PostMapping("/model-artifact-installations/{installationId}/load")
    public ApiResponse<?> load(
            @PathVariable String installationId,
            @RequestBody(required = false) Map<String, Object> request
    ) {
        return ApiResponse.ok(service.createActionJob(installationId, "load", request == null ? Map.of() : request));
    }

    @PostMapping("/model-artifact-installations/{installationId}/unload")
    public ApiResponse<?> unload(
            @PathVariable String installationId,
            @RequestBody(required = false) Map<String, Object> request
    ) {
        return ApiResponse.ok(service.createActionJob(installationId, "unload", request == null ? Map.of() : request));
    }

    @GetMapping("/model-artifact-installations/{installationId}/uninstall-impact")
    public ApiResponse<?> uninstallImpact(@PathVariable String installationId) {
        return ApiResponse.ok(service.uninstallImpact(installationId));
    }

    @DeleteMapping("/model-artifact-installations/{installationId}")
    public ApiResponse<?> uninstall(
            @PathVariable String installationId,
            @RequestParam(required = false) String operator,
            @RequestParam(required = false) String reason
    ) {
        return ApiResponse.ok(service.createUninstallJob(installationId, operator, reason));
    }

    @GetMapping("/model-artifact-jobs")
    public ApiResponse<?> jobs(@RequestParam(required = false) String deploymentId) {
        return ApiResponse.ok(Map.of("jobs", service.jobs(deploymentId)));
    }

    @GetMapping("/model-artifact-jobs/{jobId}")
    public ApiResponse<?> job(@PathVariable String jobId) {
        return ApiResponse.ok(service.job(jobId));
    }

    @GetMapping(value = "/model-artifact-jobs/{jobId}/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter events(
            @PathVariable String jobId,
            @RequestParam(defaultValue = "0") long afterSequence
    ) {
        service.job(jobId);
        return events.subscribe(jobId, afterSequence);
    }
}
