package com.test.musichouduan.service.impl;

import com.test.musichouduan.dto.MusicTypeDTO;
import com.test.musichouduan.dto.PageResult;
import com.test.musichouduan.dto.PlaylistTypeDTO;
import com.test.musichouduan.dto.SingerTypeDTO;
import com.test.musichouduan.entity.MusicType;
import com.test.musichouduan.entity.PlaylistType;
import com.test.musichouduan.entity.SingerType;
import com.test.musichouduan.exception.BusinessException;
import com.test.musichouduan.repository.MusicRepository;
import com.test.musichouduan.repository.MusicTypeRepository;
import com.test.musichouduan.repository.PlaylistRepository;
import com.test.musichouduan.repository.PlaylistTypeRepository;
import com.test.musichouduan.repository.SingerRepository;
import com.test.musichouduan.repository.SingerTypeRepository;
import com.test.musichouduan.service.TypeService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import jakarta.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 类型服务实现类
 */
@Service
public class TypeServiceImpl implements TypeService {

    @Autowired
    private MusicTypeRepository musicTypeRepository;

    @Autowired
    private SingerTypeRepository singerTypeRepository;

    @Autowired
    private PlaylistTypeRepository playlistTypeRepository;

    @Autowired
    private MusicRepository musicRepository;

    @Autowired
    private SingerRepository singerRepository;

    @Autowired
    private PlaylistRepository playlistRepository;

    @Override
    public List<MusicTypeDTO> getMusicTypeList() {
        List<MusicType> types = musicTypeRepository.findAll(Sort.by(Sort.Direction.ASC, "id"));
        return types.stream()
                .map(this::convertToMusicTypeDTO)
                .collect(Collectors.toList());
    }

    @Override
    public PageResult<MusicTypeDTO> getMusicTypePage(Integer page, Integer size, String keyword) {
        // 构建查询条件
        Specification<MusicType> spec = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            // 关键字查询
            if (StringUtils.hasText(keyword)) {
                predicates.add(cb.like(root.get("name"), "%" + keyword + "%"));
            }
            
            return cb.and(predicates.toArray(new Predicate[0]));
        };
        
        // 执行查询
        Page<MusicType> typePage = musicTypeRepository.findAll(
                spec,
                PageRequest.of(page - 1, size, Sort.by(Sort.Direction.ASC, "id"))
        );
        
        // 转换为DTO
        List<MusicTypeDTO> typeDTOs = typePage.getContent().stream()
                .map(this::convertToMusicTypeDTO)
                .collect(Collectors.toList());
        
        return new PageResult<>(
                typeDTOs,
                typePage.getTotalElements(),
                page,
                size
        );
    }

    @Override
    @Transactional
    public MusicTypeDTO addMusicType(MusicTypeDTO musicTypeDTO) {
        // 检查名称是否已存在
        if (musicTypeRepository.existsByName(musicTypeDTO.getName())) {
            throw new BusinessException("音乐类型名称已存在");
        }
        
        // 创建音乐类型实体
        MusicType musicType = new MusicType();
        musicType.setName(musicTypeDTO.getName());
        musicType.setDescription(musicTypeDTO.getDescription());
        
        // 保存音乐类型
        MusicType savedMusicType = musicTypeRepository.save(musicType);
        
        return convertToMusicTypeDTO(savedMusicType);
    }

    @Override
    @Transactional
    public MusicTypeDTO updateMusicType(Long id, MusicTypeDTO musicTypeDTO) {
        // 获取音乐类型
        MusicType musicType = musicTypeRepository.findById(id)
                .orElseThrow(() -> new BusinessException("音乐类型不存在"));
        
        // 检查名称是否已存在
        if (!musicType.getName().equals(musicTypeDTO.getName()) && 
                musicTypeRepository.existsByName(musicTypeDTO.getName())) {
            throw new BusinessException("音乐类型名称已存在");
        }
        
        // 更新音乐类型信息
        musicType.setName(musicTypeDTO.getName());
        musicType.setDescription(musicTypeDTO.getDescription());
        
        // 保存音乐类型
        MusicType updatedMusicType = musicTypeRepository.save(musicType);
        
        return convertToMusicTypeDTO(updatedMusicType);
    }

    @Override
    @Transactional
    public boolean deleteMusicType(Long id) {
        // 获取音乐类型
        MusicType musicType = musicTypeRepository.findById(id)
                .orElseThrow(() -> new BusinessException("音乐类型不存在"));
        
        // 检查是否有音乐使用该类型
        if (musicRepository.existsByTypesContaining(musicType)) {
            throw new BusinessException("该音乐类型下有音乐，无法删除");
        }
        
        // 删除音乐类型
        musicTypeRepository.delete(musicType);
        
        return true;
    }

    @Override
    public List<SingerTypeDTO> getSingerTypeList() {
        List<SingerType> types = singerTypeRepository.findAll(Sort.by(Sort.Direction.ASC, "id"));
        return types.stream()
                .map(this::convertToSingerTypeDTO)
                .collect(Collectors.toList());
    }

    @Override
    public PageResult<SingerTypeDTO> getSingerTypePage(Integer page, Integer size, String keyword) {
        // 构建查询条件
        Specification<SingerType> spec = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            // 关键字查询
            if (StringUtils.hasText(keyword)) {
                predicates.add(cb.like(root.get("name"), "%" + keyword + "%"));
            }
            
            return cb.and(predicates.toArray(new Predicate[0]));
        };
        
        // 执行查询
        Page<SingerType> typePage = singerTypeRepository.findAll(
                spec,
                PageRequest.of(page - 1, size, Sort.by(Sort.Direction.ASC, "id"))
        );
        
        // 转换为DTO
        List<SingerTypeDTO> typeDTOs = typePage.getContent().stream()
                .map(this::convertToSingerTypeDTO)
                .collect(Collectors.toList());
        
        return new PageResult<>(
                typeDTOs,
                typePage.getTotalElements(),
                page,
                size
        );
    }

    @Override
    @Transactional
    public SingerTypeDTO addSingerType(SingerTypeDTO singerTypeDTO) {
        // 检查名称是否已存在
        if (singerTypeRepository.existsByName(singerTypeDTO.getName())) {
            throw new BusinessException("歌手类型名称已存在");
        }
        
        // 创建歌手类型实体
        SingerType singerType = new SingerType();
        singerType.setName(singerTypeDTO.getName());
        singerType.setDescription(singerTypeDTO.getDescription());
        
        // 保存歌手类型
        SingerType savedSingerType = singerTypeRepository.save(singerType);
        
        return convertToSingerTypeDTO(savedSingerType);
    }

    @Override
    @Transactional
    public SingerTypeDTO updateSingerType(Long id, SingerTypeDTO singerTypeDTO) {
        // 获取歌手类型
        SingerType singerType = singerTypeRepository.findById(id)
                .orElseThrow(() -> new BusinessException("歌手类型不存在"));
        
        // 检查名称是否已存在
        if (!singerType.getName().equals(singerTypeDTO.getName()) && 
                singerTypeRepository.existsByName(singerTypeDTO.getName())) {
            throw new BusinessException("歌手类型名称已存在");
        }
        
        // 更新歌手类型信息
        singerType.setName(singerTypeDTO.getName());
        singerType.setDescription(singerTypeDTO.getDescription());
        
        // 保存歌手类型
        SingerType updatedSingerType = singerTypeRepository.save(singerType);
        
        return convertToSingerTypeDTO(updatedSingerType);
    }

    @Override
    @Transactional
    public boolean deleteSingerType(Long id) {
        // 获取歌手类型
        SingerType singerType = singerTypeRepository.findById(id)
                .orElseThrow(() -> new BusinessException("歌手类型不存在"));
        
        // 检查是否有歌手使用该类型
        if (singerRepository.existsByType(singerType)) {
            throw new BusinessException("该歌手类型下有歌手，无法删除");
        }
        
        // 删除歌手类型
        singerTypeRepository.delete(singerType);
        
        return true;
    }

    @Override
    public List<PlaylistTypeDTO> getPlaylistTypeList() {
        List<PlaylistType> types = playlistTypeRepository.findAll(Sort.by(Sort.Direction.ASC, "id"));
        return types.stream()
                .map(this::convertToPlaylistTypeDTO)
                .collect(Collectors.toList());
    }

    @Override
    public PageResult<PlaylistTypeDTO> getPlaylistTypePage(Integer page, Integer size, String keyword) {
        // 构建查询条件
        Specification<PlaylistType> spec = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            // 关键字查询
            if (StringUtils.hasText(keyword)) {
                predicates.add(cb.like(root.get("name"), "%" + keyword + "%"));
            }
            
            return cb.and(predicates.toArray(new Predicate[0]));
        };
        
        // 执行查询
        Page<PlaylistType> typePage = playlistTypeRepository.findAll(
                spec,
                PageRequest.of(page - 1, size, Sort.by(Sort.Direction.ASC, "id"))
        );
        
        // 转换为DTO
        List<PlaylistTypeDTO> typeDTOs = typePage.getContent().stream()
                .map(this::convertToPlaylistTypeDTO)
                .collect(Collectors.toList());
        
        return new PageResult<>(
                typeDTOs,
                typePage.getTotalElements(),
                page,
                size
        );
    }

    @Override
    @Transactional
    public PlaylistTypeDTO addPlaylistType(PlaylistTypeDTO playlistTypeDTO) {
        // 检查名称是否已存在
        if (playlistTypeRepository.existsByName(playlistTypeDTO.getName())) {
            throw new BusinessException("歌单类型名称已存在");
        }
        
        // 创建歌单类型实体
        PlaylistType playlistType = new PlaylistType();
        playlistType.setName(playlistTypeDTO.getName());
        playlistType.setDescription(playlistTypeDTO.getDescription());
        
        // 保存歌单类型
        PlaylistType savedPlaylistType = playlistTypeRepository.save(playlistType);
        
        return convertToPlaylistTypeDTO(savedPlaylistType);
    }

    @Override
    @Transactional
    public PlaylistTypeDTO updatePlaylistType(Long id, PlaylistTypeDTO playlistTypeDTO) {
        // 获取歌单类型
        PlaylistType playlistType = playlistTypeRepository.findById(id)
                .orElseThrow(() -> new BusinessException("歌单类型不存在"));
        
        // 检查名称是否已存在
        if (!playlistType.getName().equals(playlistTypeDTO.getName()) && 
                playlistTypeRepository.existsByName(playlistTypeDTO.getName())) {
            throw new BusinessException("歌单类型名称已存在");
        }
        
        // 更新歌单类型信息
        playlistType.setName(playlistTypeDTO.getName());
        playlistType.setDescription(playlistTypeDTO.getDescription());
        
        // 保存歌单类型
        PlaylistType updatedPlaylistType = playlistTypeRepository.save(playlistType);
        
        return convertToPlaylistTypeDTO(updatedPlaylistType);
    }

    @Override
    @Transactional
    public boolean deletePlaylistType(Long id) {
        // 获取歌单类型
        PlaylistType playlistType = playlistTypeRepository.findById(id)
                .orElseThrow(() -> new BusinessException("歌单类型不存在"));
        
        // 检查是否有歌单使用该类型
        if (playlistRepository.existsByType(playlistType)) {
            throw new BusinessException("该歌单类型下有歌单，无法删除");
        }
        
        // 删除歌单类型
        playlistTypeRepository.delete(playlistType);
        
        return true;
    }

    /**
     * 将音乐类型实体转换为DTO
     *
     * @param musicType 音乐类型实体
     * @return 音乐类型DTO
     */
    private MusicTypeDTO convertToMusicTypeDTO(MusicType musicType) {
        MusicTypeDTO musicTypeDTO = new MusicTypeDTO();
        BeanUtils.copyProperties(musicType, musicTypeDTO);
        return musicTypeDTO;
    }

    /**
     * 将歌手类型实体转换为DTO
     *
     * @param singerType 歌手类型实体
     * @return 歌手类型DTO
     */
    private SingerTypeDTO convertToSingerTypeDTO(SingerType singerType) {
        SingerTypeDTO singerTypeDTO = new SingerTypeDTO();
        BeanUtils.copyProperties(singerType, singerTypeDTO);
        return singerTypeDTO;
    }

    /**
     * 将歌单类型实体转换为DTO
     *
     * @param playlistType 歌单类型实体
     * @return 歌单类型DTO
     */
    private PlaylistTypeDTO convertToPlaylistTypeDTO(PlaylistType playlistType) {
        PlaylistTypeDTO playlistTypeDTO = new PlaylistTypeDTO();
        BeanUtils.copyProperties(playlistType, playlistTypeDTO);
        return playlistTypeDTO;
    }
}
