package net.northking.cctp.se.component;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import net.northking.cctp.common.http.ResultWrapper;
import net.northking.cctp.se.config.AtuServerConfig;
import net.northking.cctp.se.util.HttpUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 组件库加载定时任务
 */
@Component
public class LibraryUpdateSchedule {

    private static final Logger logger = LoggerFactory.getLogger(LibraryUpdateSchedule.class);

    private final long INITIAL_DELAY = 30*1000L;
    private final long FIXED_DELAY = 2*60*1000L;

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private AtuServerConfig atuServerConfig;
    @Autowired
    private ComponentManagementService comService;

    private static final ObjectMapper objectMapper = new ObjectMapper();
    /**
     * 定时请求平台获取最新组件库清单
     * 对比本地加载的库进行组件库版本更新
     */
    @Scheduled(initialDelay = INITIAL_DELAY,fixedDelay = FIXED_DELAY)
    public void libUpdate(){
        //获取最新组件库清单
        String url = atuServerConfig.getServerUrl()+atuServerConfig.getLibListUrl();
        List<ComLibraryInfoDto> list = new ArrayList<>();
        try {
            Map<String, String> map = new HashMap<>();
            String responseBody = restTemplate.postForObject(url, map, String.class);
            ResultWrapper<List<ComLibraryInfoDto>> wrapper = objectMapper.readValue(responseBody,
                    new TypeReference<ResultWrapper<List<ComLibraryInfoDto>>>(){});
            // 获取最新版本号。
            list= wrapper.getData();
        }catch (Exception e){
            logger.error("组件库清单获取失败  终止更新   失败原因-----------"+e.getMessage());
            return;
        }
        //获取当前已加载组件库清单
        Map<String,String> existMap = comService.getExistMap();
        //对比清单获取需要更新组件库
        List<ComLibraryInfoDto> updateList = comparedVersion(existMap,list);
        if (updateList.size()>0){
            logger.info("组件库更新校验完毕 下载新库文件ing-----------");
            //下载组件库文件
            for (ComLibraryInfoDto info : updateList) {
                //下载文件，并设置路径
                info.setLocalPath(downloadLibFile(info));
            }
            //调取服务加载组件库
            logger.info("组件库下载完毕 热加载更新ing-----------");
            comService.reloadLibrary(updateList);
            logger.info("组件库更新检查 ----------------- 结束");
        }
    }

    /**
     * 对比现有组件库，找出需要更新的组件库清单
     * @param existMap
     * @param list
     * @return
     */
    private List<ComLibraryInfoDto> comparedVersion(Map<String, String> existMap, List<ComLibraryInfoDto> list) {
        List<ComLibraryInfoDto> newList = new ArrayList<>();
        for (ComLibraryInfoDto info : list) {
            String libName = info.getLibraryName();
            if(!(existMap.containsKey(libName) && info.getLibraryVersion().equals(existMap.get(libName)))){
                //未加载或者版本有变动，重新加载组件库
                newList.add(info);
            }
        }
        return newList;
    }

    private String downloadLibFile(ComLibraryInfoDto info){
        String fileId = info.getFilePath();
        String classPath = "./library/";
        File check = new File(classPath);
        if(!check.exists()){
            check.mkdirs();
        }
        String saveName = classPath+info.getFileName();
        File save = new File(saveName);
        try {
            String urlPath = info.getTenantId() + info.getFilePath().replace("/", "_");
            InputStream is = HttpUtils.download2Stream(urlPath);
            FileOutputStream fos = new FileOutputStream(save);
            FileCopyUtils.copy(is,fos);
            fos.flush();
            is.close();
            fos.close();
        }catch (IOException e){
            logger.info("组件库：【{}】 下载失败，失败原因：{}",info.getLibraryName(),e.getMessage());
        }
        logger.info("组件库【{}】下载完毕 保存路径：{}",info.getLibraryName(),save.getPath());
        return saveName;
    }
}
