package com.sino.mci.admin.controller;

import com.sun.net.httpserver.HttpServer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.UUID;

import static com.sino.mci.test.AuthTestHelper.createTenantAndLogin;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
@Transactional
public class TenantWebhookControllerTest {

    @Autowired
    private MockMvc mockMvc;

    private HttpServer localServer;

    @AfterEach
    void stopLocalServer() {
        if (localServer != null) {
            localServer.stop(0);
            localServer = null;
        }
    }

    @Test
    void shouldReturnCurrentTenantWebhookConfig() throws Exception {
        String tenantCode = "wh-" + UUID.randomUUID().toString().substring(0, 8);
        String authToken = createTenantAndLogin(mockMvc, tenantCode, "Webhook 测试");

        mockMvc.perform(get("/msg-platform/api/v1/account/tenant/webhook")
                        .contextPath("/msg-platform")
                        .header("Authorization", authToken)
                        .header("X-Tenant-Code", tenantCode))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(0))
                .andExpect(jsonPath("$.data.inbound_webhook_url").isEmpty())
                .andExpect(jsonPath("$.data.auth_config").isMap());
    }

    @Test
    void shouldUpdateWebhookConfig() throws Exception {
        String tenantCode = "wh-" + UUID.randomUUID().toString().substring(0, 8);
        String authToken = createTenantAndLogin(mockMvc, tenantCode, "Webhook 测试");

        String payload = "{\"inbound_webhook_url\":\"https://example.com/webhook\",\"auth_config\":{\"sign_algorithm\":\"hmac-sha256\",\"webhook_secret\":\"secret-123\"}}";

        mockMvc.perform(post("/msg-platform/api/v1/account/tenant/webhook")
                        .contextPath("/msg-platform")
                        .header("Authorization", authToken)
                        .header("X-Tenant-Code", tenantCode)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(payload))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(0))
                .andExpect(jsonPath("$.data.inbound_webhook_url").value("https://example.com/webhook"))
                .andExpect(jsonPath("$.data.auth_config.sign_algorithm").value("hmac-sha256"))
                .andExpect(jsonPath("$.data.auth_config.webhook_secret").value("secret-123"));

        mockMvc.perform(get("/msg-platform/api/v1/account/tenant/webhook")
                        .contextPath("/msg-platform")
                        .header("Authorization", authToken)
                        .header("X-Tenant-Code", tenantCode))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(0))
                .andExpect(jsonPath("$.data.inbound_webhook_url").value("https://example.com/webhook"))
                .andExpect(jsonPath("$.data.auth_config.webhook_secret").value("secret-123"));
    }

    @Test
    void shouldReturnSuccessWhenTestWebhookReceives2xx() throws Exception {
        String tenantCode = "wh-" + UUID.randomUUID().toString().substring(0, 8);
        String authToken = createTenantAndLogin(mockMvc, tenantCode, "Webhook 测试");

        updateWebhookConfig(authToken, tenantCode);

        int port = startLocalHttpServer(200, "ok");

        mockMvc.perform(post("/msg-platform/api/v1/account/tenant/webhook/test")
                        .contextPath("/msg-platform")
                        .header("Authorization", authToken)
                        .header("X-Tenant-Code", tenantCode)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(String.format("{\"url\":\"http://localhost:%d/webhook\"}", port)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(0))
                .andExpect(jsonPath("$.data.success").value(true))
                .andExpect(jsonPath("$.data.message").value("测试推送成功，HTTP 200 OK"));
    }

    @Test
    void shouldReturnFailureWhenTestWebhookThrows() throws Exception {
        String tenantCode = "wh-" + UUID.randomUUID().toString().substring(0, 8);
        String authToken = createTenantAndLogin(mockMvc, tenantCode, "Webhook 测试");

        updateWebhookConfig(authToken, tenantCode);

        mockMvc.perform(post("/msg-platform/api/v1/account/tenant/webhook/test")
                        .contextPath("/msg-platform")
                        .header("Authorization", authToken)
                        .header("X-Tenant-Code", tenantCode)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content("{\"url\":\"http://localhost:1/webhook\"}"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(0))
                .andExpect(jsonPath("$.data.success").value(false))
                .andExpect(jsonPath("$.data.message").value(org.hamcrest.Matchers.containsString("Connection refused")));
    }

    private void updateWebhookConfig(String authToken, String tenantCode) throws Exception {
        String payload = "{\"inbound_webhook_url\":\"https://example.com/webhook\",\"auth_config\":{\"sign_algorithm\":\"hmac-sha256\",\"webhook_secret\":\"secret-123\"}}";
        mockMvc.perform(post("/msg-platform/api/v1/account/tenant/webhook")
                        .contextPath("/msg-platform")
                        .header("Authorization", authToken)
                        .header("X-Tenant-Code", tenantCode)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(payload))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(0));
    }

    private int startLocalHttpServer(int statusCode, String responseBody) throws IOException {
        localServer = HttpServer.create(new InetSocketAddress(0), 0);
        localServer.createContext("/webhook", exchange -> {
            byte[] bytes = responseBody.getBytes();
            exchange.sendResponseHeaders(statusCode, bytes.length);
            exchange.getResponseBody().write(bytes);
            exchange.close();
        });
        localServer.start();
        return localServer.getAddress().getPort();
    }
}
