package com.mosquito.project.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mosquito.project.dto.ActivityGraphResponse;
import com.mosquito.project.dto.ActivityStatsResponse;
import com.mosquito.project.service.ActivityService;
import com.mosquito.project.support.TestAuthSupport;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.MockMvc;

import java.util.List;

import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(ActivityController.class)
@Import(com.mosquito.project.config.ControllerTestConfig.class)
@TestPropertySource(properties = {
    "spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration," +
    "org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration," +
    "org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration"
})
class ActivityStatsAndGraphControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @MockBean
    private ActivityService activityService;

    @Test
    void shouldReturnStats_whenActivityExists() throws Exception {
        ActivityStatsResponse mock = new ActivityStatsResponse(220, 110,
            List.of(new ActivityStatsResponse.DailyStats("2025-09-28", 100, 50)));
        when(activityService.getActivityStats(1L)).thenReturn(mock);

        mockMvc.perform(get("/api/v1/activities/1/stats")
                .accept(MediaType.APPLICATION_JSON)
                .header("X-API-Key", TestAuthSupport.RAW_API_KEY)
                .header("Authorization", "Bearer test-token"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data.totalParticipants").value(220))
            .andExpect(jsonPath("$.data.totalShares").value(110))
            .andExpect(jsonPath("$.data.dailyStats[0].date").value("2025-09-28"));
    }

    @Test
    void shouldReturnGraph_whenActivityExists() throws Exception {
        ActivityGraphResponse graph = new ActivityGraphResponse(
            List.of(new ActivityGraphResponse.Node("1", "用户1")),
            List.of(new ActivityGraphResponse.Edge("1", "2"))
        );
        when(activityService.getActivityGraph(1L, null, 3, 1000)).thenReturn(graph);

        mockMvc.perform(get("/api/v1/activities/1/graph")
                .accept(MediaType.APPLICATION_JSON)
                .header("X-API-Key", TestAuthSupport.RAW_API_KEY)
                .header("Authorization", "Bearer test-token"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data.nodes").exists())
            .andExpect(jsonPath("$.data.edges").exists());
    }

    @Test
    void shouldRespectRootAndDepthParams() throws Exception {
        ActivityGraphResponse graph = new ActivityGraphResponse(
            List.of(new ActivityGraphResponse.Node("1", "用户1"), new ActivityGraphResponse.Node("2", "用户2")),
            List.of(new ActivityGraphResponse.Edge("1", "2"))
        );
        when(activityService.getActivityGraph(1L, 1L, 1, 10)).thenReturn(graph);

        mockMvc.perform(get("/api/v1/activities/1/graph")
                .param("rootUserId", "1")
                .param("maxDepth", "1")
                .param("limit", "10")
                .accept(MediaType.APPLICATION_JSON)
                .header("X-API-Key", TestAuthSupport.RAW_API_KEY)
                .header("Authorization", "Bearer test-token"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data.nodes").isArray())
            .andExpect(jsonPath("$.data.edges[0].from").value("1"));
    }

    @Test
    void shouldIncludePaginationMeta_onLeaderboard() throws Exception {
        when(activityService.getLeaderboard(1L)).thenReturn(
            List.of(
                new com.mosquito.project.domain.LeaderboardEntry(1L, "用户1", 1000),
                new com.mosquito.project.domain.LeaderboardEntry(2L, "用户2", 900),
                new com.mosquito.project.domain.LeaderboardEntry(3L, "用户3", 800)
            )
        );

        mockMvc.perform(get("/api/v1/activities/1/leaderboard")
                .param("page", "0")
                .param("size", "2")
                .accept(MediaType.APPLICATION_JSON)
                .header("X-API-Key", TestAuthSupport.RAW_API_KEY)
                .header("Authorization", "Bearer test-token"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.meta.pagination.total").value(3))
            .andExpect(jsonPath("$.data[0].userId").value(1));
    }
}
