package com.cameleer.server.app.controller;

import com.cameleer.server.app.AbstractPostgresIT;
import com.cameleer.server.app.TestSecurityHelper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.core.io.ByteArrayResource;

import static org.assertj.core.api.Assertions.assertThat;

class DeploymentControllerIT extends AbstractPostgresIT {

    @Autowired
    private TestRestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private TestSecurityHelper securityHelper;

    private String operatorJwt;
    private String adminJwt;
    private String defaultEnvId;
    private String appId;
    private String appSlugRef;
    private String versionId;

    @BeforeEach
    void setUp() throws Exception {
        operatorJwt = securityHelper.operatorToken();
        adminJwt = securityHelper.adminToken();

        // Clean up
        jdbcTemplate.update("DELETE FROM deployments");
        jdbcTemplate.update("DELETE FROM app_versions");
        jdbcTemplate.update("DELETE FROM apps");

        // Ensure test-operator exists in users table (required for deployments.created_by FK)
        jdbcTemplate.update(
                "INSERT INTO users (user_id, provider, display_name) VALUES ('test-operator', 'local', 'Test Operator') ON CONFLICT (user_id) DO NOTHING");

        // Get default environment ID
        ResponseEntity<String> envResponse = restTemplate.exchange(
                "/api/v1/admin/environments", HttpMethod.GET,
                new HttpEntity<>(securityHelper.authHeadersNoBody(adminJwt)),
                String.class);
        JsonNode envs = objectMapper.readTree(envResponse.getBody());
        for (JsonNode env : envs) {
            if ("default".equals(env.path("slug").asText())) {
                defaultEnvId = env.path("id").asText();
                break;
            }
        }

        // Create app (slug becomes the path identifier)
        String appSlug = "deploy-test";
        String appJson = String.format("""
                {"slug": "%s", "displayName": "Deploy Test"}
                """, appSlug);
        ResponseEntity<String> appResponse = restTemplate.exchange(
                "/api/v1/environments/default/apps", HttpMethod.POST,
                new HttpEntity<>(appJson, securityHelper.authHeaders(operatorJwt)),
                String.class);
        appId = objectMapper.readTree(appResponse.getBody()).path("id").asText();
        appSlugRef = appSlug;

        // Upload a JAR version
        byte[] jarContent = "fake-jar-for-deploy".getBytes();
        ByteArrayResource resource = new ByteArrayResource(jarContent) {
            @Override
            public String getFilename() {
                return "deploy-test.jar";
            }
        };
        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add("file", resource);
        HttpHeaders headers = new HttpHeaders();
        headers.set("Authorization", "Bearer " + operatorJwt);
        headers.set("X-Cameleer-Protocol-Version", "1");
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        ResponseEntity<String> versionResponse = restTemplate.exchange(
                "/api/v1/environments/default/apps/" + appSlug + "/versions", HttpMethod.POST,
                new HttpEntity<>(body, headers),
                String.class);
        versionId = objectMapper.readTree(versionResponse.getBody()).path("id").asText();
    }

    @Test
    void deploy_asOperator_returns202() throws Exception {
        // Deploy creates a record; the async executor will fail (no Docker) but the record should exist
        String json = String.format("""
                {"appVersionId": "%s"}
                """, versionId);

        ResponseEntity<String> response = restTemplate.exchange(
                "/api/v1/environments/default/apps/" + appSlugRef + "/deployments", HttpMethod.POST,
                new HttpEntity<>(json, securityHelper.authHeaders(operatorJwt)),
                String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED);
        JsonNode body = objectMapper.readTree(response.getBody());
        assertThat(body.path("status").asText()).isEqualTo("STARTING");
        assertThat(body.path("containerName").asText()).isEqualTo("default-deploy-test");
        assertThat(body.has("id")).isTrue();
    }

    @Test
    void listDeployments_asOperator_returnsDeployments() throws Exception {
        // Create a deployment first
        String json = String.format("""
                {"appVersionId": "%s"}
                """, versionId);
        restTemplate.exchange(
                "/api/v1/environments/default/apps/" + appSlugRef + "/deployments", HttpMethod.POST,
                new HttpEntity<>(json, securityHelper.authHeaders(operatorJwt)),
                String.class);

        ResponseEntity<String> response = restTemplate.exchange(
                "/api/v1/environments/default/apps/" + appSlugRef + "/deployments", HttpMethod.GET,
                new HttpEntity<>(securityHelper.authHeadersNoBody(operatorJwt)),
                String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
        JsonNode body = objectMapper.readTree(response.getBody());
        assertThat(body.isArray()).isTrue();
        assertThat(body.size()).isGreaterThanOrEqualTo(1);
    }

    @Test
    void getDeployment_notFound_returns404() {
        ResponseEntity<String> response = restTemplate.exchange(
                "/api/v1/environments/default/apps/" + appSlugRef + "/deployments/00000000-0000-0000-0000-000000000000",
                HttpMethod.GET,
                new HttpEntity<>(securityHelper.authHeadersNoBody(operatorJwt)),
                String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
    }
}
