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 AppControllerIT extends AbstractPostgresIT {

    @Autowired
    private TestRestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private TestSecurityHelper securityHelper;

    private String operatorJwt;
    private String viewerJwt;
    private String defaultEnvId;

    @BeforeEach
    void setUp() throws Exception {
        operatorJwt = securityHelper.operatorToken();
        viewerJwt = securityHelper.viewerToken();

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

        // Get default environment ID
        ResponseEntity<String> envResponse = restTemplate.exchange(
                "/api/v1/admin/environments", HttpMethod.GET,
                new HttpEntity<>(securityHelper.authHeadersNoBody(securityHelper.adminToken())),
                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;
            }
        }
        assertThat(defaultEnvId).isNotNull();
    }

    @Test
    void createApp_asOperator_returns201() throws Exception {
        String json = """
                {"slug": "my-app", "displayName": "My App"}
                """;

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

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
        JsonNode body = objectMapper.readTree(response.getBody());
        assertThat(body.path("slug").asText()).isEqualTo("my-app");
        assertThat(body.path("displayName").asText()).isEqualTo("My App");
        assertThat(body.path("environmentId").asText()).isEqualTo(defaultEnvId);
    }

    @Test
    void listApps_asOperator_returnsCreatedApp() throws Exception {
        // Create an app first
        String json = """
                {"slug": "list-test", "displayName": "List Test"}
                """;
        restTemplate.exchange(
                "/api/v1/environments/default/apps", HttpMethod.POST,
                new HttpEntity<>(json, securityHelper.authHeaders(operatorJwt)),
                String.class);

        ResponseEntity<String> response = restTemplate.exchange(
                "/api/v1/environments/default/apps", 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 createApp_asViewer_returns403() {
        String json = """
                {"slug": "viewer-app", "displayName": "Viewer App"}
                """;

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

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

    @Test
    void uploadJar_asOperator_returns201() throws Exception {
        String appSlug = "jar-test";
        // Create app
        String json = String.format("""
                {"slug": "%s", "displayName": "JAR Test"}
                """, appSlug);
        restTemplate.exchange(
                "/api/v1/environments/default/apps", HttpMethod.POST,
                new HttpEntity<>(json, securityHelper.authHeaders(operatorJwt)),
                String.class);

        // Upload JAR (fake content)
        byte[] jarContent = "fake-jar-content".getBytes();
        ByteArrayResource resource = new ByteArrayResource(jarContent) {
            @Override
            public String getFilename() {
                return "test-app.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> response = restTemplate.exchange(
                "/api/v1/environments/default/apps/" + appSlug + "/versions", HttpMethod.POST,
                new HttpEntity<>(body, headers),
                String.class);

        assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
        JsonNode version = objectMapper.readTree(response.getBody());
        assertThat(version.path("version").asInt()).isEqualTo(1);
        assertThat(version.path("jarChecksum").asText()).isNotEmpty();
        assertThat(version.path("jarFilename").asText()).isEqualTo("test-app.jar");
    }
}
