package com.test.musichouduan.controller.admin;

import cn.dev33.satoken.annotation.SaCheckRole;
import com.test.musichouduan.dto.Result;
import com.test.musichouduan.dto.admin.DashboardDataDTO;
import com.test.musichouduan.dto.admin.MusicAdminDTO;
import com.test.musichouduan.dto.admin.StatItemDTO;
import com.test.musichouduan.dto.admin.UserAdminDTO;
import com.test.musichouduan.entity.Music;
import com.test.musichouduan.entity.PlaylistType;
import com.test.musichouduan.entity.User;
import com.test.musichouduan.repository.MusicRepository;
import com.test.musichouduan.repository.PlayHistoryRepository;
import com.test.musichouduan.repository.PlaylistRepository;
import com.test.musichouduan.repository.SingerRepository;
import com.test.musichouduan.repository.UserRepository;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 后台管理控制台控制器
 */
@Tag(name = "后台管理控制台接口", description = "提供后台管理控制台所需的统计数据")
@RestController
@RequestMapping("/api/admin/dashboard")
@SaCheckRole("admin")
public class AdminDashboardController {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private MusicRepository musicRepository;

    @Autowired
    private PlaylistRepository playlistRepository;

    @Autowired
    private SingerRepository singerRepository;

    @Autowired
    private PlayHistoryRepository playHistoryRepository;

    @PersistenceContext
    private EntityManager entityManager;

    /**
     * 获取控制台统计数据
     *
     * @return 统计数据
     */
    @Operation(summary = "获取控制台统计数据", description = "获取用户数量、音乐数量、歌单数量、歌手数量等统计数据")
    @GetMapping("/stats")
    public Result<DashboardDataDTO> getStats() {
        try {
            DashboardDataDTO data = new DashboardDataDTO();

            // 统计基础数据
            long userCount = userRepository.count();
            long musicCount = musicRepository.count();
            long playlistCount = playlistRepository.count();
            long singerCount = singerRepository.count();
            long playCount = musicRepository.sumPlayCount();

            data.setUserCount(userCount);
            data.setMusicCount(musicCount);
            data.setPlaylistCount(playlistCount);
            data.setSingerCount(singerCount);
            data.setPlayCount(playCount);

            // 获取最近7天的用户增长数据
            data.setUserGrowth(getUserGrowthData());

            // 获取音乐类型分布数据
            data.setMusicTypeDistribution(getTypeDistribution());

            // 获取最近7天的播放量数据
            data.setPlayCountData(getPlayCountData());

            // 获取最新用户
            List<User> users = userRepository.findLatestUsers(PageRequest.of(0, 5));
            List<UserAdminDTO> latestUsers = users.stream()
                    .map(UserAdminDTO::fromEntity)
                    .collect(Collectors.toList());
            data.setLatestUsers(latestUsers);

            // 获取最新音乐
            List<Music> musics = musicRepository.findLatest(PageRequest.of(0, 5));
            List<MusicAdminDTO> latestMusics = musics.stream()
                    .map(MusicAdminDTO::fromEntity)
                    .collect(Collectors.toList());
            data.setLatestMusics(latestMusics);

            return Result.success(data);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("获取控制台统计数据失败");
        }
    }

    /**
     * 获取最近7天的用户增长数据
     *
     * @return 用户增长数据
     */
    private List<StatItemDTO> getUserGrowthData() {
        List<StatItemDTO> result = new ArrayList<>();
        LocalDate today = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd");

        // 获取最近7天的日期
        for (int i = 6; i >= 0; i--) {
            LocalDate date = today.minusDays(i);
            LocalDateTime startOfDay = date.atStartOfDay();
            LocalDateTime endOfDay = date.plusDays(1).atStartOfDay().minusNanos(1);

            // 统计当天注册的用户数量
            long count = userRepository.countByCreateTimeBetween(startOfDay, endOfDay);

            StatItemDTO item = new StatItemDTO();
            item.setName(date.format(formatter));
            item.setValue(count);
            result.add(item);
        }

        return result;
    }

    /**
     * 获取音乐、歌单、歌手类型分布数据
     *
     * @return 类型分布数据
     */
    private List<StatItemDTO> getTypeDistribution() {
        List<StatItemDTO> result = new ArrayList<>();

        // 音乐类型分布
        StatItemDTO musicTypeStat = new StatItemDTO();
        musicTypeStat.setName("音乐类型");

        try {
            List<Object[]> musicTypeData = musicRepository.countByMusicType();
            List<StatItemDTO> musicTypeChildren = musicTypeData.stream().map(item -> {
                StatItemDTO child = new StatItemDTO();
                child.setName((String) item[0]);
                child.setValue(((Number) item[1]).longValue());
                return child;
            }).collect(Collectors.toList());
            musicTypeStat.setChildren(musicTypeChildren);
        } catch (Exception e) {
            e.printStackTrace();
            // 如果查询失败，返回空列表
            musicTypeStat.setChildren(new ArrayList<>());
        }

        result.add(musicTypeStat);

        // 歌单类型分布
        StatItemDTO playlistTypeStat = new StatItemDTO();
        playlistTypeStat.setName("歌单类型");

        // 使用原生 SQL 查询或者手动聚合数据
        List<PlaylistType> playlistTypes = entityManager.createQuery("SELECT DISTINCT pt FROM PlaylistType pt", PlaylistType.class).getResultList();
        List<StatItemDTO> playlistTypeChildren = new ArrayList<>();

        for (PlaylistType type : playlistTypes) {
            Long count = playlistRepository.countByType(type);
            StatItemDTO child = new StatItemDTO();
            child.setName(type.getName());
            child.setValue(count);
            playlistTypeChildren.add(child);
        }

        playlistTypeStat.setChildren(playlistTypeChildren);
        result.add(playlistTypeStat);

        // 歌手类型分布
        StatItemDTO singerTypeStat = new StatItemDTO();
        singerTypeStat.setName("歌手类型");

        // 使用原生 SQL 查询或者手动聚合数据
        List<com.test.musichouduan.entity.SingerType> singerTypes = entityManager.createQuery("SELECT DISTINCT st FROM SingerType st", com.test.musichouduan.entity.SingerType.class).getResultList();
        List<StatItemDTO> singerTypeChildren = new ArrayList<>();

        for (com.test.musichouduan.entity.SingerType type : singerTypes) {
            Long count = singerRepository.countByType(type);
            StatItemDTO child = new StatItemDTO();
            child.setName(type.getName());
            child.setValue(count);
            singerTypeChildren.add(child);
        }

        singerTypeStat.setChildren(singerTypeChildren);
        result.add(singerTypeStat);

        return result;
    }

    /**
     * 获取最近7天的播放量数据
     *
     * @return 播放量数据
     */
    private List<StatItemDTO> getPlayCountData() {
        List<StatItemDTO> result = new ArrayList<>();
        LocalDate today = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd");

        // 获取最近7天的日期
        for (int i = 6; i >= 0; i--) {
            LocalDate date = today.minusDays(i);
            LocalDateTime startOfDay = date.atStartOfDay();
            LocalDateTime endOfDay = date.plusDays(1).atStartOfDay().minusNanos(1);

            // 统计当天的播放量
            long count = playHistoryRepository.countByPlayTimeBetween(startOfDay, endOfDay);

            StatItemDTO item = new StatItemDTO();
            item.setName(date.format(formatter));
            item.setValue(count);
            result.add(item);
        }

        return result;
    }
}
