package tech.easyflow.chatlog.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Assert;
import org.junit.Test;
import tech.easyflow.chatlog.domain.command.ChatAppendMessageCommand;
import tech.easyflow.chatlog.domain.command.ChatSessionSummaryCommand;
import tech.easyflow.chatlog.domain.command.ChatSessionUpsertCommand;
import tech.easyflow.chatlog.domain.event.ChatPersistEvent;
import tech.easyflow.chatlog.domain.event.ChatPersistEventType;
import tech.easyflow.chatlog.repository.mysql.MySqlChatLogRepository;
import tech.easyflow.chatlog.repository.mysql.MySqlChatLogTableManager;
import tech.easyflow.chatlog.repository.mysql.MySqlChatRoundRepository;
import tech.easyflow.chatlog.repository.mysql.MySqlChatSessionRepository;
import tech.easyflow.chatlog.support.ChatJsonSupport;

import java.math.BigInteger;
import java.time.YearMonth;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class ChatPersistMySqlApplyServiceTest {

    private final ChatPersistMySqlApplyService service =
            new ChatPersistMySqlApplyService(null, null, null, null, new ChatJsonSupport(new ObjectMapper()));

    @Test
    public void shouldBuildMissingSessionUpsertFromMessageMetadata() {
        ChatAppendMessageCommand first = new ChatAppendMessageCommand();
        first.setSessionId(BigInteger.valueOf(101));
        first.setTenantId(BigInteger.ONE);
        first.setDeptId(BigInteger.TEN);
        first.setUserId(BigInteger.valueOf(12));
        first.setUserAccount("admin");
        first.setAssistantId(BigInteger.valueOf(99));
        first.setAssistantCode("test-bot");
        first.setAssistantName("测试助手");
        first.setSessionTitle("你是谁");
        first.setCreatedBy(BigInteger.valueOf(12));
        first.setCreated(new Date(1_000L));

        ChatAppendMessageCommand second = new ChatAppendMessageCommand();
        second.setSessionId(BigInteger.valueOf(101));
        second.setTenantId(BigInteger.ONE);
        second.setDeptId(BigInteger.TEN);
        second.setUserId(BigInteger.valueOf(12));
        second.setAssistantId(BigInteger.valueOf(99));
        second.setCreatedBy(BigInteger.valueOf(12));
        second.setCreated(new Date(2_000L));

        List<ChatSessionUpsertCommand> upserts = service.buildSessionUpserts(List.of(first, second));

        Assert.assertEquals(1, upserts.size());
        ChatSessionUpsertCommand upsert = upserts.get(0);
        Assert.assertEquals(BigInteger.valueOf(101), upsert.getSessionId());
        Assert.assertEquals("admin", upsert.getUserAccount());
        Assert.assertEquals("test-bot", upsert.getAssistantCode());
        Assert.assertEquals("测试助手", upsert.getAssistantName());
        Assert.assertEquals("你是谁", upsert.getTitle());
        Assert.assertEquals(new Date(2_000L), upsert.getOperateAt());
    }

    @Test
    public void shouldKeepTitleBlankWhenMessageMetadataMissing() {
        ChatAppendMessageCommand command = new ChatAppendMessageCommand();
        command.setSessionId(BigInteger.valueOf(202));
        command.setTenantId(BigInteger.ONE);
        command.setDeptId(BigInteger.ONE);
        command.setUserId(BigInteger.valueOf(7));
        command.setAssistantId(BigInteger.valueOf(8));
        command.setCreatedBy(BigInteger.valueOf(7));
        command.setCreated(new Date(3_000L));

        List<ChatSessionUpsertCommand> upserts = service.buildSessionUpserts(List.of(command));

        Assert.assertEquals(1, upserts.size());
        ChatSessionUpsertCommand upsert = upserts.get(0);
        Assert.assertEquals("", upsert.getUserAccount());
        Assert.assertNull(upsert.getTitle());
        Assert.assertEquals(BigInteger.valueOf(7), upsert.getOperatorId());
    }

    @Test
    public void shouldNotDoubleCountSummaryWhenMessageEventReplayed() {
        ChatJsonSupport jsonSupport = new ChatJsonSupport(new ObjectMapper());
        FakeSessionRepository sessionRepository = new FakeSessionRepository();
        FakeLogRepository logRepository = new FakeLogRepository(jsonSupport);
        ChatPersistMySqlApplyService applyService = new ChatPersistMySqlApplyService(
                sessionRepository,
                logRepository,
                new FakeRoundRepository(),
                new FakeTableManager(),
                jsonSupport
        );
        ChatAppendMessageCommand command = new ChatAppendMessageCommand();
        command.setMessageId(BigInteger.valueOf(301));
        command.setSessionId(BigInteger.valueOf(401));
        command.setTenantId(BigInteger.ONE);
        command.setDeptId(BigInteger.ONE);
        command.setUserId(BigInteger.valueOf(7));
        command.setAssistantId(BigInteger.valueOf(8));
        command.setSenderId(BigInteger.valueOf(7));
        command.setSenderName("admin");
        command.setSenderRole("user");
        command.setContentText("第一条消息");
        command.setCreatedBy(BigInteger.valueOf(7));
        command.setCreated(new Date(4_000L));

        ChatPersistEvent event = new ChatPersistEvent();
        event.setEventId("message-301");
        event.setEventType(ChatPersistEventType.USER_MESSAGE_APPENDED);
        event.setSessionId(command.getSessionId());
        event.setPayload(jsonSupport.toJson(command));

        applyService.apply(List.of(event));
        applyService.apply(List.of(event));

        Assert.assertEquals(1, sessionRepository.summaryCommands.size());
        ChatSessionSummaryCommand summaryCommand = sessionRepository.summaryCommands.get(0);
        Assert.assertEquals(1, summaryCommand.getMessageIncrement());
        Assert.assertEquals("第一条消息", summaryCommand.getLastMessagePreview());
        Assert.assertEquals(new Date(4_000L), summaryCommand.getLastMessageAt());
        Assert.assertEquals(new Date(4_000L), summaryCommand.getAccessAt());
    }

    private static final class FakeSessionRepository extends MySqlChatSessionRepository {

        private final List<ChatSessionSummaryCommand> summaryCommands = new ArrayList<>();

        private FakeSessionRepository() {
            super(null, null);
        }

        @Override
        public void createOrTouchBatch(List<ChatSessionUpsertCommand> commands) {
        }

        @Override
        public void updateSummaries(List<ChatSessionSummaryCommand> commands) {
            summaryCommands.addAll(commands);
        }
    }

    private static final class FakeLogRepository extends MySqlChatLogRepository {

        private boolean inserted;

        private FakeLogRepository(ChatJsonSupport jsonSupport) {
            super(null, null, jsonSupport);
        }

        @Override
        public List<ChatAppendMessageCommand> appendMessages(List<ChatAppendMessageCommand> commands) {
            if (inserted) {
                return List.of();
            }
            inserted = true;
            return commands;
        }
    }

    private static final class FakeRoundRepository extends MySqlChatRoundRepository {

        private FakeRoundRepository() {
            super(null);
        }
    }

    private static final class FakeTableManager extends MySqlChatLogTableManager {

        private FakeTableManager() {
            super(null, null);
        }

        @Override
        public void ensureMonthTable(YearMonth month) {
        }
    }
}
