package com.cfdeployer.service;

import com.cfdeployer.model.CfDeployRequest;
import com.cfdeployer.model.CfDeployResponse;
import com.cfdeployer.model.DeploymentStatus;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.nio.file.Path;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
@RequiredArgsConstructor
@Slf4j
public class AsyncDeploymentService {

    private final CfCliService cfCliService;
    private final Map<String, DeploymentStatus> deploymentStatuses = new ConcurrentHashMap<>();

    @Async
    public void deployAsync(String sessionId, CfDeployRequest request, Path jarPath, Path manifestPath) {
        log.info("Starting async deployment for session: {}", sessionId);

        // Set initial status
        deploymentStatuses.put(sessionId, DeploymentStatus.builder()
                .uploadSessionId(sessionId)
                .status(DeploymentStatus.Status.IN_PROGRESS)
                .message("Deployment in progress...")
                .progress(0)
                .build());

        try {
            // Update progress
            updateProgress(sessionId, 10, "Logging into Cloud Foundry...");

            CfDeployResponse response = cfCliService.deployApplicationFromPaths(request, jarPath, manifestPath);

            updateProgress(sessionId, 100, "Deployment completed");

            // Set final status
            if (Boolean.TRUE.equals(response.getSuccess())) {
                deploymentStatuses.put(sessionId, DeploymentStatus.builder()
                        .uploadSessionId(sessionId)
                        .status(DeploymentStatus.Status.COMPLETED)
                        .message(response.getMessage())
                        .output(response.getOutput())
                        .progress(100)
                        .build());
            } else {
                deploymentStatuses.put(sessionId, DeploymentStatus.builder()
                        .uploadSessionId(sessionId)
                        .status(DeploymentStatus.Status.FAILED)
                        .message(response.getMessage())
                        .error(response.getError())
                        .progress(0)
                        .build());
            }

        } catch (Exception e) {
            log.error("Async deployment failed for session: {}", sessionId, e);
            deploymentStatuses.put(sessionId, DeploymentStatus.builder()
                    .uploadSessionId(sessionId)
                    .status(DeploymentStatus.Status.FAILED)
                    .message("Deployment failed: " + e.getMessage())
                    .error(e.toString())
                    .progress(0)
                    .build());
        }
    }

    public DeploymentStatus getDeploymentStatus(String sessionId) {
        DeploymentStatus status = deploymentStatuses.get(sessionId);
        if (status == null) {
            return DeploymentStatus.builder()
                    .uploadSessionId(sessionId)
                    .status(DeploymentStatus.Status.PENDING)
                    .message("No deployment found for this session")
                    .build();
        }
        return status;
    }

    public void clearDeploymentStatus(String sessionId) {
        deploymentStatuses.remove(sessionId);
        log.debug("Cleared deployment status for session: {}", sessionId);
    }

    private void updateProgress(String sessionId, int progress, String message) {
        DeploymentStatus current = deploymentStatuses.get(sessionId);
        if (current != null) {
            current.setProgress(progress);
            current.setMessage(message);
            log.info("Session {}: {} ({}%)", sessionId, message, progress);
        }
    }
}
