package cn.efunbox.audio.impl;

import cn.efunbox.audio.consts.MediaType;
import cn.efunbox.audio.entity.Album;
import cn.efunbox.audio.entity.Audio;
import cn.efunbox.audio.page.OnePage;
import cn.efunbox.audio.repository.AlbumRepo;
import cn.efunbox.audio.repository.AudioRepo;
import cn.efunbox.audio.repository.AudioRepoImpl;
import cn.efunbox.audio.service.AudioService;
import cn.efunbox.audio.utils.ApiResult;
import cn.efunbox.audio.vo.SearchVO;
import javazoom.jl.decoder.Bitstream;
import javazoom.jl.decoder.Header;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.BufferedInputStream;
import java.math.BigInteger;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Created by yao on 17-9-26.
 */
@Slf4j
@Service
public class AudioServiceImpl implements AudioService {

    @Autowired
    AudioRepo audioRepo;
    @Autowired
    AlbumRepo albumRepo;
    @Autowired
    AudioRepoImpl audioRepoImpl;

    @Value("${efunbox.oss.img.url}")
    private String imgURL;

    @Override
    public Audio GetOne(Long id){
        Audio audio = audioRepo.findById(id);
        return audio;
    }

    @Override
    public Page<Audio> SearchAll(int mediaType, int page, int size){
        if(size<=0)
            size = 50;
        Pageable pageable = new PageRequest(page, size);
        Page<Audio> list = null;
        if(mediaType== MediaType.AUDIO.getCode() || mediaType==MediaType.VIDEO.getCode())
            list = audioRepo.findByMediaType(mediaType, pageable);
        else
            list = audioRepo.findAll(pageable);

        fillAlbum(list.getContent());

        return list;
    }

    private void fillAlbum(List<Audio> list) {

        List<BigInteger> albumIds = new ArrayList<>();
        list.stream().forEach(audio -> albumIds.add(audio.getAlbumId()));

        List<Album> albumList = albumRepo.findByIdIn(albumIds);

        if (CollectionUtils.isEmpty(albumList)) {
            return;
        }

        Map<BigInteger, Album> albumMap = albumList.stream().collect(Collectors.toMap(Album::getId, album -> album));

        list.stream().forEach(audio -> {
            Album album = albumMap.get(audio.getAlbumId());
            if (Objects.nonNull(album)) {
                audio.setProductPackage(album.getProductPackage());
                audio.setAlbum(album.getName());
                if (StringUtils.isNotBlank(album.getImage())) {
                    audio.setAlbumImage(imgURL + album.getImage());
                }
            }
        });

    }

    @Override
    public Page<Audio> SearchByIdGroup(int mediaType, Long idGroup, int page, int size){
        if(size<=0)
            size = 50;
        Pageable pageable = new PageRequest(page, size);
        Page<Audio> list = null;
        if(mediaType== MediaType.AUDIO.getCode() || mediaType==MediaType.VIDEO.getCode())
            list = audioRepo.findByMediaTypeAndIdGroup(mediaType, idGroup, pageable);
        else
            list = audioRepo.findByIdGroup(idGroup, pageable);
        fillAlbum(list.getContent());
        return list;
    }

    @Override
    public List<Audio> SearchByName(int mediaType, String name){
        if(name==null || name.isEmpty())
            return null;
        List<Audio> list = null;
        if(mediaType== MediaType.AUDIO.getCode() || mediaType==MediaType.VIDEO.getCode())
            list = audioRepo.findByMediaTypeAndName(mediaType, name);
        else
            list = audioRepo.findByName(name);
//        System.out.println("list1:"+list.toString());

        if(CollectionUtils.isEmpty(list)){
            list = audioRepo.findByNameLike(name);
            System.out.println("list:"+list.toString());
        }
        fillAlbum(list);
//        System.out.println("list2:"+list.toString());
        return list;
    }

    @Override
    public List<Audio> SearchByAlbum(int mediaType, String album){
        if(album==null || album.isEmpty())
            return null;

        List<BigInteger> albumIds = albumRepo.findIdsByNameLike(album);
        List<Audio> list = null;
        if(mediaType== MediaType.AUDIO.getCode() || mediaType==MediaType.VIDEO.getCode())
            list = audioRepo.findByMediaTypeAndAlbumIdIn(mediaType, albumIds);
        else
            list = audioRepo.findByAlbumIdIn(albumIds);
        fillAlbum(list);
        return list;
    }

    @Override
    public List<Audio> SearchByNameAlbum(int mediaType, String name, String album){
        if(name==null || name.isEmpty()
                || album==null || album.isEmpty())
            return null;
        List<BigInteger> albumIds = albumRepo.findIdsByNameLike(album);
        List<Audio> list = null;
        if(mediaType== MediaType.AUDIO.getCode() || mediaType==MediaType.VIDEO.getCode())
            list = audioRepo.findByMediaTypeAndNameAndAlbumIdIn(mediaType, name, albumIds);
        else
            list = audioRepo.findByNameAndAlbumIdIn(name, albumIds);
        if(CollectionUtils.isEmpty(list))
            list = audioRepo.findByNameLikeAndAlbumIdIn(name, albumIds);

        fillAlbum(list);
        return list;
    }

    @Override
    public Audio Insert(Audio audio){
        Audio a = audioRepo.save(audio);
        return a;
    }

    @Override
    public void Delete(Long id){
        audioRepo.delete(id);
    }

    @Override
    public OnePage<Audio> pageList(Audio audio, Integer pageNo, Integer pageSize) {

        long count = audioRepo.count(audio);

        OnePage onePage = new OnePage(count,pageNo,pageSize);

        if (count == 0) {
            return onePage;
        }



        List<Audio> audios = audioRepo.find(audio, onePage.getStart(),onePage.getPageSize());

        fillAlbum(audios);
        onePage.setList(audios);

        return onePage;
    }

    @Override
    public OnePage<Audio> searchList(SearchVO searchVO) {

        Album searchAlbum = fillSearchAlbum(searchVO);

        List<Album> albumList = albumRepo.find(searchAlbum);

        if (CollectionUtils.isEmpty(albumList)) {
            return new OnePage(0L,searchVO.getPageNo(),searchVO.getPageSize());
        }

        List<BigInteger> albumIds = new ArrayList<>();
        albumList.forEach(album -> albumIds.add(album.getId()));

        searchVO.setIdAlbums(albumIds);

        Long count = audioRepoImpl.count(searchVO);
        if (Objects.isNull(count)) {
            count = 0L;
        }
        OnePage<Audio> onePage = new OnePage(count,searchVO.getPageNo(),searchVO.getPageSize());
        if (count == 0) {
            return onePage;
        }



        List<Audio> audioList = audioRepoImpl.findAudio(searchVO, onePage.getStart(), onePage.getPageSize());
        fillAlbum(audioList);
        onePage.setList(audioList);

        return onePage;
    }

    private Album fillSearchAlbum(SearchVO searchVO) {
        Album album = new Album();
        album.setId(searchVO.getAlbumId());
        album.setMediaType(searchVO.getMediaType());
        if (StringUtils.isNotBlank(searchVO.getAlbum())) {
            album.setName("%" + searchVO.getAlbum() + "%");
        }
        if (StringUtils.isNotBlank(searchVO.getAge())) {
            album.setAge("%" + searchVO.getAge() + "%");
        }
        if (StringUtils.isNotBlank(searchVO.getLanguage())) {
            album.setLanguage("%" + searchVO.getLanguage() + "%");
        }
        if (StringUtils.isNotBlank(searchVO.getSubject())) {
            album.setSubject("%" + searchVO.getSubject() + "%");
        }
        if (StringUtils.isNotBlank(searchVO.getSuitableCrowd())) {
            album.setSuitableCrowd("%" + searchVO.getSuitableCrowd() + "%");
        }
        if (StringUtils.isNotBlank(searchVO.getVersion())) {
            album.setVersion("%" + searchVO.getVersion() + "%");
        }
        if (StringUtils.isNotBlank(searchVO.getVolume())) {
            album.setVolume("%" + searchVO.getVolume() + "%");
        }

        return album;
    }

    @Override
    public Audio getAudioInfo(Long id) {

        if (Objects.isNull(id) || id < 1) {
            return null;
        }

        Audio audio = audioRepo.find(id);

        if (Objects.isNull(audio)) {
            return null;
        }

        Album album = albumRepo.find(audio.getAlbumId());
        if (Objects.nonNull(album)) {
            audio.setAlbum(album.getName());
            if (StringUtils.isNotBlank(album.getImage())) {
                audio.setAlbumImage(imgURL + album.getImage());
            }
        }

        return audio;
    }

    @Override
    public ApiResult countTime() {

        //TODO
        List<Audio> allAudio = audioRepo.findAll();
        List<Audio> newAudioList = new ArrayList<>();
        long startTime = System.currentTimeMillis();
        allAudio.forEach(audio -> {
            long timeLength = getMicrosecondLength(audio.getUrl());
            audio.setTotalTime(timeLength);
            newAudioList.add(audio);
        });
        List<Audio> update = audioRepo.update(newAudioList);
        System.out.println("耗时 :" +  (System.currentTimeMillis() - startTime));
        return ApiResult.ok(update.size());
    }

    /**
     * 获取音频文件时长
     *
     * @param filePath wav文件路径,支持本地和网络HTTP路径
     * @return 时长/毫秒,可 /1000D 得到秒
     * @throws Exception
     */
    public static long getMicrosecondLength(String filePath) {

        long countTime = 0;
        try {
            URL urlfile = new URL(filePath);
            //File file = new File("C:\\music\\test2.mp3");
            //URL urlfile = file.toURI().toURL();
            URLConnection con = urlfile.openConnection();
            int b = con.getContentLength();// 得到音乐文件的总长度
            BufferedInputStream bis = new BufferedInputStream(con.getInputStream());
            Bitstream bt = new Bitstream(bis);
            Header h = bt.readFrame();
            int time = (int) h.total_ms(b);
//            System.out.println(time / 1000);
            countTime = time/1000;
        } catch (Exception e) {
//            e.printStackTrace();
            log.error("get time is error! url : {}" ,filePath);
        } finally {
            return countTime;
        }


    }

}