package com.sino.mci.channel.wechat.personal;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.sino.mci.channel.common.dto.ChannelInitRequest;
import com.sino.mci.channel.common.dto.ChannelInitResult;
import com.sino.mci.channel.common.dto.SendMessageRequest;
import com.sino.mci.channel.common.dto.SendMessageResult;
import com.sino.mci.channel.common.model.ChannelType;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.Map;

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

class WechatPersonalChannelAdapterTest {

    private MockWebServer mockWebServer;
    private WechatPersonalChannelAdapter adapter;

    @BeforeEach
    void setUp() throws Exception {
        mockWebServer = new MockWebServer();
        mockWebServer.start();

        WechatPersonalProperties properties = new WechatPersonalProperties();
        properties.setBaseUrl(mockWebServer.url("/").toString());

        adapter = new WechatPersonalChannelAdapter(properties);
    }

    @AfterEach
    void tearDown() throws Exception {
        mockWebServer.shutdown();
    }

    @Test
    void shouldReturnChannelType() {
        assertThat(adapter.getChannelType()).isEqualTo(ChannelType.WECHAT_PERSONAL);
    }

    @Test
    void shouldInitAccountAndReturnQrCodeUrl() throws InterruptedException {
        mockWebServer.enqueue(new MockResponse()
                .setResponseCode(200)
                .setHeader("Content-Type", "application/json")
                .setBody(toJson(Map.of(
                        "login_id", "login-123",
                        "qr_code_url", "https://example.com/qr.png",
                        "status", "pending"))));

        ChannelInitRequest request = new ChannelInitRequest();
        Map<String, Object> config = new HashMap<>();
        config.put("account_id", "wx-123");
        config.put("account_name", "Test Account");
        request.setConfig(config);

        ChannelInitResult result = adapter.initAccount(request);

        assertThat(result.isSuccess()).isTrue();
        assertThat(result.getAccountId()).isEqualTo("wx-123");
        assertThat(result.getAccountName()).isEqualTo("Test Account");
        assertThat(result.getQrCodeUrl()).isEqualTo("https://example.com/qr.png");

        RecordedRequest recorded = mockWebServer.takeRequest();
        assertThat(recorded.getMethod()).isEqualTo("POST");
        assertThat(recorded.getPath()).isEqualTo("/v1/wechat-personal/login/start");
        assertThat(recorded.getBody().readUtf8()).contains("wx-123", "Test Account");
    }

    @Test
    void shouldFailInitAccountWhenQrCodeMissing() {
        mockWebServer.enqueue(new MockResponse()
                .setResponseCode(200)
                .setHeader("Content-Type", "application/json")
                .setBody(toJson(Map.of(
                        "login_id", "login-123",
                        "status", "error"))));

        ChannelInitRequest request = new ChannelInitRequest();
        Map<String, Object> config = new HashMap<>();
        config.put("account_id", "wx-123");
        request.setConfig(config);

        ChannelInitResult result = adapter.initAccount(request);

        assertThat(result.isSuccess()).isFalse();
        assertThat(result.getMessage()).contains("未返回二维码");
    }

    @Test
    void shouldSendTextMessage() throws InterruptedException {
        mockWebServer.enqueue(new MockResponse()
                .setResponseCode(200)
                .setHeader("Content-Type", "application/json")
                .setBody(toJson(Map.of(
                        "accepted", true,
                        "message_id", "msg-123"))));

        SendMessageRequest request = new SendMessageRequest();
        request.setConversationId("chat-123");
        request.setContentType("text");
        Map<String, Object> content = new HashMap<>();
        content.put("text", "hello");
        request.setContent(content);
        Map<String, Object> extra = new HashMap<>();
        extra.put("account_id", "wx-123");
        extra.put("record_id", "1001");
        extra.put("tenant_code", "rescue");
        request.setExtra(extra);

        SendMessageResult result = adapter.sendMessage(request);

        assertThat(result.isSuccess()).isTrue();
        assertThat(result.getChannelMessageId()).isEqualTo("msg-123");

        RecordedRequest recorded = mockWebServer.takeRequest();
        assertThat(recorded.getMethod()).isEqualTo("POST");
        assertThat(recorded.getPath()).isEqualTo("/v1/wechat-personal/send/text");
        String body = recorded.getBody().readUtf8();
        assertThat(body).contains("wx-123", "chat-123", "hello", "1001", "rescue");
    }

    @Test
    void shouldSendImageMessage() throws InterruptedException {
        mockWebServer.enqueue(new MockResponse()
                .setResponseCode(200)
                .setHeader("Content-Type", "application/json")
                .setBody(toJson(Map.of(
                        "accepted", true,
                        "message_id", "img-123"))));

        SendMessageRequest request = new SendMessageRequest();
        request.setConversationId("chat-456");
        request.setContentType("image");
        Map<String, Object> content = new HashMap<>();
        content.put("image_url", "https://example.com/img.png");
        request.setContent(content);
        Map<String, Object> extra = new HashMap<>();
        extra.put("account_id", "wx-123");
        extra.put("record_id", "1002");
        extra.put("tenant_code", "rescue");
        request.setExtra(extra);

        SendMessageResult result = adapter.sendMessage(request);

        assertThat(result.isSuccess()).isTrue();
        assertThat(result.getChannelMessageId()).isEqualTo("img-123");

        RecordedRequest recorded = mockWebServer.takeRequest();
        assertThat(recorded.getPath()).isEqualTo("/v1/wechat-personal/send/image");
        String body = recorded.getBody().readUtf8();
        assertThat(body).contains("wx-123", "1002", "rescue", "https://example.com/img.png");
    }

    @Test
    void shouldReturnFailureWhenPythonReportsError() {
        mockWebServer.enqueue(new MockResponse()
                .setResponseCode(200)
                .setHeader("Content-Type", "application/json")
                .setBody(toJson(Map.of(
                        "success", false,
                        "error", "account wx-123 not registered"))));

        SendMessageRequest request = new SendMessageRequest();
        request.setConversationId("chat-123");
        request.setContentType("text");
        Map<String, Object> content = new HashMap<>();
        content.put("text", "hello");
        request.setContent(content);
        Map<String, Object> extra = new HashMap<>();
        extra.put("account_id", "wx-123");
        request.setExtra(extra);

        SendMessageResult result = adapter.sendMessage(request);

        assertThat(result.isSuccess()).isFalse();
        assertThat(result.getMessage()).contains("account wx-123 not registered");
    }

    @Test
    void shouldReturnFailureWhenAccountIdMissing() {
        SendMessageRequest request = new SendMessageRequest();
        request.setConversationId("chat-123");
        request.setContentType("text");
        request.setContent(Map.of("text", "hello"));

        SendMessageResult result = adapter.sendMessage(request);

        assertThat(result.isSuccess()).isFalse();
        assertThat(result.getMessage()).contains("account_id");
    }

    @Test
    void shouldParseCallback() {
        assertThat(adapter.parseCallback("raw-body").getChannelType())
                .isEqualTo(ChannelType.WECHAT_PERSONAL.name());
        assertThat(adapter.parseCallback("raw-body").getRawBody()).isEqualTo("raw-body");
    }

    private String toJson(Object value) {
        try {
            return new ObjectMapper().writeValueAsString(value);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
