package com.ycwl.basic.puzzle.service.impl;

import com.ycwl.basic.biz.FaceStatusManager;
import com.ycwl.basic.puzzle.dto.PuzzleGenerateRequest;
import com.ycwl.basic.puzzle.dto.PuzzleGenerateResponse;
import com.ycwl.basic.puzzle.edge.task.PuzzleEdgeRenderTaskService;
import com.ycwl.basic.puzzle.entity.PuzzleElementEntity;
import com.ycwl.basic.puzzle.entity.PuzzleGenerationRecordEntity;
import com.ycwl.basic.puzzle.entity.PuzzleTemplateEntity;
import com.ycwl.basic.puzzle.fill.FillResult;
import com.ycwl.basic.puzzle.fill.PuzzleElementFillEngine;
import com.ycwl.basic.puzzle.mapper.PuzzleGenerationRecordMapper;
import com.ycwl.basic.puzzle.repository.PuzzleRepository;
import com.ycwl.basic.puzzle.service.IPuzzleGenerateService;
import com.ycwl.basic.puzzle.test.PuzzleTestDataBuilder;
import com.ycwl.basic.puzzle.util.PuzzleDuplicationDetector;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.pc.processor.PuzzleRelationProcessor;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class PuzzleGenerateServiceImplTest {

    @Mock
    private PuzzleRepository puzzleRepository;
    @Mock
    private PuzzleGenerationRecordMapper recordMapper;
    @Mock
    private PuzzleElementFillEngine fillEngine;
    @Mock
    private ScenicRepository scenicRepository;
    @Mock
    private PuzzleDuplicationDetector duplicationDetector;
    @Mock
    private PuzzleEdgeRenderTaskService puzzleEdgeRenderTaskService;
    @Mock
    private FaceStatusManager faceStatusManager;
    @Mock
    private PuzzleRelationProcessor puzzleRelationProcessor;

    @InjectMocks
    private PuzzleGenerateServiceImpl service;

    @Test
    void shouldRejectWhenTemplateScenicMismatch() {
        PuzzleTemplateEntity template = PuzzleTestDataBuilder.createBasicTemplate();
        template.setScenicId(100L);

        when(puzzleRepository.getTemplateByCode("ticket")).thenReturn(template);

        PuzzleGenerateRequest request = new PuzzleGenerateRequest();
        request.setTemplateCode("ticket");
        request.setScenicId(200L);
        request.setFaceId(88L);

        IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> service.generate(request));
        assertTrue(ex.getMessage().contains("模板不属于当前景区"));
        verify(puzzleRepository, never()).getElementsByTemplateId(anyLong());
    }

    @Test
    void shouldUseTemplateScenicAndTriggerFillEngine() {
        PuzzleTemplateEntity template = PuzzleTestDataBuilder.createBasicTemplate();
        template.setScenicId(9L);

        PuzzleElementEntity element = PuzzleTestDataBuilder.createTextElement(
                template.getId(), "realName", 0, 0, 100, 30, 1, "默认", 16, "#000000"
        );

        when(puzzleRepository.getTemplateByCode("ticket")).thenReturn(template);
        when(puzzleRepository.getElementsByTemplateId(template.getId())).thenReturn(new ArrayList<>(List.of(element)));
        when(faceStatusManager.isPuzzleSourceChanged(anyLong(), anyLong(), anyInt())).thenReturn(true);
        when(fillEngine.execute(eq(template.getId()), eq(88L), anyLong()))
                .thenReturn(FillResult.matched("test-rule", Map.of("faceImage", "https://images.test/a.png"), 1));

        // Mock 边缘渲染任务
        when(puzzleEdgeRenderTaskService.createRenderTask(any(), any(), any(), any(), any(), any()))
                .thenReturn(100L);
        when(puzzleEdgeRenderTaskService.waitForTask(anyLong(), anyLong()))
                .thenReturn(PuzzleEdgeRenderTaskService.TaskWaitResult.success("https://oss.example.com/puzzle/final.png"));

        doAnswer(invocation -> {
            PuzzleGenerationRecordEntity record = invocation.getArgument(0);
            record.setId(555L);
            return 1;
        }).when(recordMapper).insert(any());

        // Mock 获取更新后的记录
        PuzzleGenerationRecordEntity updatedRecord = new PuzzleGenerationRecordEntity();
        updatedRecord.setId(555L);
        updatedRecord.setResultImageUrl("https://oss.example.com/puzzle/final.png");
        updatedRecord.setResultFileSize(12345L);
        updatedRecord.setResultWidth(750);
        updatedRecord.setResultHeight(1334);
        when(recordMapper.getById(555L)).thenReturn(updatedRecord);

        PuzzleGenerateRequest request = new PuzzleGenerateRequest();
        request.setTemplateCode("ticket");
        request.setScenicId(9L);
        request.setFaceId(88L);
        request.setDynamicData(Map.of("orderNo", "A001"));

        PuzzleGenerateResponse response = service.generate(request);

        assertNotNull(response);
        assertEquals("https://oss.example.com/puzzle/final.png", response.getImageUrl());

        verify(fillEngine).execute(template.getId(), 88L, 9L);
        ArgumentCaptor<PuzzleGenerationRecordEntity> captor =
                ArgumentCaptor.forClass(PuzzleGenerationRecordEntity.class);
        verify(recordMapper).insert(captor.capture());
        assertEquals(9L, captor.getValue().getScenicId());
    }

    @Test
    void shouldSkipFillEngineWhenScenicMissing() {
        PuzzleTemplateEntity template = PuzzleTestDataBuilder.createBasicTemplate();
        template.setScenicId(null);

        PuzzleElementEntity element = PuzzleTestDataBuilder.createTextElement(
                template.getId(), "username", 0, 0, 100, 30, 1, "fallback", 14, "#000"
        );

        when(puzzleRepository.getTemplateByCode("ticket")).thenReturn(template);
        when(puzzleRepository.getElementsByTemplateId(template.getId())).thenReturn(new ArrayList<>(List.of(element)));
        when(faceStatusManager.isPuzzleSourceChanged(anyLong(), anyLong(), anyInt())).thenReturn(true);

        // Mock 边缘渲染任务
        when(puzzleEdgeRenderTaskService.createRenderTask(any(), any(), any(), any(), any(), any()))
                .thenReturn(100L);
        when(puzzleEdgeRenderTaskService.waitForTask(anyLong(), anyLong()))
                .thenReturn(PuzzleEdgeRenderTaskService.TaskWaitResult.success("https://oss.example.com/puzzle/default.png"));

        doAnswer(invocation -> {
            PuzzleGenerationRecordEntity record = invocation.getArgument(0);
            record.setId(777L);
            return 1;
        }).when(recordMapper).insert(any());

        // Mock 获取更新后的记录
        PuzzleGenerationRecordEntity updatedRecord = new PuzzleGenerationRecordEntity();
        updatedRecord.setId(777L);
        updatedRecord.setResultImageUrl("https://oss.example.com/puzzle/default.png");
        updatedRecord.setResultFileSize(12345L);
        updatedRecord.setResultWidth(750);
        updatedRecord.setResultHeight(1334);
        when(recordMapper.getById(777L)).thenReturn(updatedRecord);

        PuzzleGenerateRequest request = new PuzzleGenerateRequest();
        request.setTemplateCode("ticket");
        request.setFaceId(188L); // 缺少scenicId

        service.generate(request);

        // fillEngine 不会被调用，因为没有 scenicId
        verify(fillEngine, never()).execute(anyLong(), anyLong(), anyLong());
    }
}
