package com.infoepoch.pms.agent.tool.union.care.provider;

import com.infoepoch.pms.agent.observability.ai.AiObservationContext;
import com.infoepoch.pms.agent.observability.ai.AiObservationSupport;
import com.infoepoch.pms.agent.observability.ai.ObservedRestClientFactory;
import com.infoepoch.pms.agent.properties.AiObservabilityProperties;
import com.infoepoch.pms.agent.domain.care.model.PagedResult;
import com.infoepoch.pms.agent.domain.care.model.UserProfileSummary;
import com.infoepoch.pms.agent.properties.CareBusinessProperties;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpServer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicReference;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

class HttpCareBusinessDataProviderTest {

    private HttpServer server;
    private final AtomicReference<String> latestTraceIdHeader = new AtomicReference<>();
    private final AtomicReference<String> latestRequestIdHeader = new AtomicReference<>();
    private final AtomicReference<String> latestSessionIdHeader = new AtomicReference<>();

    @AfterEach
    void tearDown() {
        if (server != null) {
            server.stop(0);
        }
    }

    @Test
    void shouldDifferentiateUsersWithSameMobileButDifferentNames() throws IOException {
        HttpCareBusinessDataProvider provider = createProvider("""
                {
                  "code": 1,
                  "msg": "ok",
                  "data": {
                    "totalCount": 2,
                    "dataList": [
                      { "name": "张三", "mobile": "13800000000", "departmentName": "一部" },
                      { "name": "李四", "mobile": "13800000000", "departmentName": "二部" }
                    ]
                  }
                }
                """);

        PagedResult<UserProfileSummary> result = provider.searchUsersByConditions(
                "trace-1",
                "session-1",
                Map.of(),
                1,
                10
        );

        assertEquals(2, result.records().size());
        assertNotEquals(result.records().get(0).userId(), result.records().get(1).userId());
    }

    @Test
    void shouldIgnoreDepartmentWhenMobileIsBlank() throws IOException {
        HttpCareBusinessDataProvider provider = createProvider("""
                {
                  "code": 1,
                  "msg": "ok",
                  "data": {
                    "totalCount": 2,
                    "dataList": [
                      { "name": "张三", "mobile": "", "departmentName": "一部" },
                      { "name": "张三", "mobile": "", "departmentName": "二部" }
                    ]
                  }
                }
                """);

        PagedResult<UserProfileSummary> result = provider.searchUsersByConditions(
                "trace-1",
                "session-1",
                Map.of(),
                1,
                10
        );

        assertEquals(2, result.records().size());
        assertEquals(result.records().get(0).userId(), result.records().get(1).userId());
    }

    @Test
    void shouldDifferentiateUsersWithSameNameButDifferentMobiles() throws IOException {
        HttpCareBusinessDataProvider provider = createProvider("""
                {
                  "code": 1,
                  "msg": "ok",
                  "data": {
                    "totalCount": 2,
                    "dataList": [
                      { "name": "张三", "mobile": "13800000000", "departmentName": "一部" },
                      { "name": "张三", "mobile": "13900000000", "departmentName": "一部" }
                    ]
                  }
                }
                """);

        PagedResult<UserProfileSummary> result = provider.searchUsersByConditions(
                "trace-1",
                "session-1",
                Map.of(),
                1,
                10
        );

        assertEquals(2, result.records().size());
        assertNotEquals(result.records().get(0).userId(), result.records().get(1).userId());
    }

    @Test
    void shouldPropagateObservationHeadersWhenSearchingUsers() throws IOException {
        HttpCareBusinessDataProvider provider = createProvider("""
                {
                  "code": 1,
                  "msg": "ok",
                  "data": {
                    "totalCount": 0,
                    "dataList": []
                  }
                }
                """);
        AiObservationSupport support = new AiObservationSupport(new AiObservabilityProperties(), "pms-agent");
        AiObservationContext context = AiObservationContext.builder()
                .traceId("trace-1")
                .requestId("request-1")
                .sessionId("session-1")
                .flowId("flow-1")
                .scene("用户检索")
                .build();

        support.withObservationContext(context, () -> {
            provider.searchUsersByConditions("trace-1", "session-1", Map.of(), 1, 10);
            return null;
        });

        assertEquals("trace-1", latestTraceIdHeader.get());
        assertEquals("request-1", latestRequestIdHeader.get());
        assertEquals("session-1", latestSessionIdHeader.get());
    }

    private HttpCareBusinessDataProvider createProvider(String responseBody) throws IOException {
        server = HttpServer.create(new InetSocketAddress(0), 0);
        server.createContext("/union-js/api/functionCallTools/getUserInfoList", exchange -> {
            latestTraceIdHeader.set(exchange.getRequestHeaders().getFirst(ObservedRestClientFactory.HEADER_TRACE_ID));
            latestRequestIdHeader.set(exchange.getRequestHeaders().getFirst(ObservedRestClientFactory.HEADER_REQUEST_ID));
            latestSessionIdHeader.set(exchange.getRequestHeaders().getFirst(ObservedRestClientFactory.HEADER_SESSION_ID));
            writeJsonResponse(exchange, responseBody);
        });
        server.start();

        CareBusinessProperties properties = new CareBusinessProperties();
        properties.setBaseUrl("http://127.0.0.1:" + server.getAddress().getPort());
        properties.setUserSearchPath("/union-js/api/functionCallTools/getUserInfoList");
        AiObservationSupport support = new AiObservationSupport(new AiObservabilityProperties(), "pms-agent");
        return new HttpCareBusinessDataProvider(
                properties,
                new ObservedRestClientFactory(support)
        );
    }

    private void writeJsonResponse(HttpExchange exchange, String responseBody) throws IOException {
        byte[] body = responseBody.getBytes(StandardCharsets.UTF_8);
        exchange.getResponseHeaders().add("Content-Type", "application/json; charset=UTF-8");
        exchange.sendResponseHeaders(200, body.length);
        try (OutputStream outputStream = exchange.getResponseBody()) {
            outputStream.write(body);
        } finally {
            exchange.close();
        }
    }
}
