package com.jiayue.ipfcst.fileupload.service;

import ch.qos.logback.classic.Logger;
import cn.hutool.core.util.StrUtil;
import com.jiayue.ipfcst.common.data.constant.enums.ChannelStatusEnum;
import com.jiayue.ipfcst.common.data.entity.UploadFileChannel;
import com.jiayue.ipfcst.common.data.entity.UploadObject;
import com.jiayue.ipfcst.common.data.repository.UploadFileChannelRepository;
import com.jiayue.ipfcst.common.data.repository.UploadURLRepository;
import com.jiayue.ipfcst.fileupload.IEC102.UploadFileNettyServer;
import com.jiayue.ipfcst.fileupload.config.AppenderFactory;
import com.jiayue.ipfcst.fileupload.util.FileConstant;
import lombok.extern.slf4j.Slf4j;
import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;
import net.sf.ehcache.search.Attribute;
import net.sf.ehcache.search.Query;
import net.sf.ehcache.search.Result;
import net.sf.ehcache.search.Results;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 上报通道业务层
 *
 * @author xsl
 * @version 3.0
 */
@Service
@Slf4j
public class UploadFileChannelService {
  @Autowired
  UploadFileChannelRepository uploadFileChannelRepository;
  @Autowired
  EhCacheCacheManager ehCacheCacheManager;
  @Autowired
  AppenderFactory appenderFactory;
  @Autowired
  UploadObjectService uploadObjectService;
  @Autowired
  UploadURLRepository uploadURLRepository;

  @Value("${fileupload.nettyServer.readerIdleTime}")
  private String readerIdleTime;

  /**
   * 保存通道
   *
   * @param uploadFileChannel 通道信息
   */
  @Transactional(propagation = Propagation.SUPPORTS)
  public UploadFileChannel save(UploadFileChannel uploadFileChannel) {
    // 获取上报对象协议类型
    List<UploadObject> uploadObjectList = uploadObjectService.get();
    UploadObject uploadObject = uploadObjectList.stream().filter(s -> s.getId().equals(uploadFileChannel.getUploadObjectId())).collect(Collectors.toList()).get(0);
    if (!"ftp".equals(uploadObject.getUploadProtocolEnum().getCode()) && !"sftp".equals(uploadObject.getUploadProtocolEnum().getCode())) {
      if (uploadFileChannel.getId() != null) {
        if ("102s".equals(uploadObject.getUploadProtocolEnum().getCode())){
          if (FileConstant.nettyInstanceMap.get(uploadFileChannel.getLocalIp() + ":" + uploadFileChannel.getLocalPort()) != null){
            FileConstant.nettyInstanceMap.get(uploadFileChannel.getLocalIp() + ":" + uploadFileChannel.getLocalPort()).destroy();
            FileConstant.nettyInstanceMap.remove(uploadFileChannel.getLocalIp() + ":" + uploadFileChannel.getLocalPort());
          }
        }
        else{
          // 102服务端，将原有的服务先销毁掉
          if (FileConstant.nettyInstanceMap.get(uploadFileChannel.getId()) != null) {
            FileConstant.nettyInstanceMap.get(uploadFileChannel.getId()).destroy();
            FileConstant.nettyInstanceMap.remove(uploadFileChannel.getId());
          }
        }
      }
    }

    UploadFileChannel uploadFileChannel1 = uploadFileChannelRepository.saveAndFlush(uploadFileChannel);

    // 创建通道对应的日志
    Logger logger = appenderFactory.getLogger(uploadObject.getUploadObjectName(), uploadObject.getUploadProtocolEnum().getMessage(), uploadObject.getObjectNo());

    String protocol = uploadObject.getUploadProtocolEnum().getCode();

    if ("102s".equals(protocol)) {
      if (FileConstant.nettyInstanceMap.get(uploadFileChannel.getLocalIp() + ":" + uploadFileChannel.getLocalPort()) == null) {
        // 创建netty服务
        UploadFileNettyServer uploadFileNettyServer = new UploadFileNettyServer(new InetSocketAddress(uploadFileChannel.getLocalIp(), Integer.parseInt(uploadFileChannel.getLocalPort())), Integer.parseInt(readerIdleTime));
        // 开启102服务端
        uploadFileNettyServer.start();
        // 将netty服务端实例保存到缓存变量，用于关闭通道时用。
        FileConstant.nettyInstanceMap.put(uploadFileChannel.getLocalIp() + ":" + uploadFileChannel.getLocalPort(), uploadFileNettyServer);
      }
    }

    clearChannelCache();
    return uploadFileChannel1;
  }
  @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public void saveCloud(UploadFileChannel bean) {
    uploadFileChannelRepository.save(bean);
  }
  @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public void saveCloud(List<UploadFileChannel> beans) {
    if(beans != null && beans.size() > 0){
      uploadFileChannelRepository.deleteAll();
      uploadFileChannelRepository.saveAll(beans);
    }
  }

  /**
   * 删除通道信息
   *
   * @param uploadFileChannel 通道信息
   */
  @Transactional(propagation = Propagation.SUPPORTS)
  public void delete(UploadFileChannel uploadFileChannel) {
    // 获取上报对象协议类型
    List<UploadObject> tempObjectList = uploadObjectService.get();
    List<UploadObject> uploadObjectList = tempObjectList.stream().filter(s -> s.getId().equals(uploadFileChannel.getUploadObjectId())).collect(Collectors.toList());
    if (uploadObjectList.size()>0){
      UploadObject uploadObject = uploadObjectList.get(0);
      if (!"ftp".equals(uploadObject.getUploadProtocolEnum().getCode()) && !"sftp".equals(uploadObject.getUploadProtocolEnum().getCode())) {
        String protocol = uploadObject.getUploadProtocolEnum().getCode();
        if ("102s".equals(protocol)) {
          String tempLocalPort = uploadFileChannel.getLocalPort();
          String tempLocalIp = uploadFileChannel.getLocalIp();
          List<UploadFileChannel> tempList = uploadFileChannelRepository.findAll();
          List<UploadFileChannel> ufList = new ArrayList<>();
          for (UploadFileChannel uf:tempList){
            if (uf.getRemoteIp()!=null && uf.getLocalPort()!=null){
              ufList.add(uf);
            }
          }

          // 过滤出是否存在多个IP和端口相同的102服务通道
          List<UploadFileChannel> filterList = ufList.stream().filter(s -> s.getLocalIp().equals(tempLocalIp) && s.getLocalPort().equals(tempLocalPort) && StrUtil.hasEmpty(s.getUploadUserName())).collect(Collectors.toList());
          if (filterList.size() == 1) {
            // 将netty服务端实例保存到缓存变量，用于关闭通道时用。
            if (FileConstant.nettyInstanceMap.get(uploadFileChannel.getLocalIp() + ":" + uploadFileChannel.getLocalPort()) != null) {
              FileConstant.nettyInstanceMap.get(uploadFileChannel.getLocalIp() + ":" + uploadFileChannel.getLocalPort()).destroy();
              FileConstant.nettyInstanceMap.remove(uploadFileChannel.getLocalIp() + ":" + uploadFileChannel.getLocalPort());
            }
          }
        } else if ("102m_sd_client".equals(protocol) || "102m_sd_server".equals(protocol)) {
          // 102服务端，将原有的服务先销毁掉
          if (FileConstant.nettyInstanceMap.get(uploadFileChannel.getId() + "") != null) {
            FileConstant.nettyInstanceMap.get(uploadFileChannel.getId() + "").destroy();
            FileConstant.nettyInstanceMap.remove(uploadFileChannel.getId() + "");
          }
        } else if ("zj102_client".equals(protocol)) {
          FileConstant.channelStatusMap.remove(uploadObject.getId() + "-" + uploadFileChannel.getId());
        }
      }
    }

    clearChannelCache();
    uploadFileChannelRepository.delete(uploadFileChannel);
  }

  /**
   * 根据ObjectId删除通道
   */
  @Transactional()
  public void deleteByObjId(Integer objId) {
    uploadFileChannelRepository.deleteAllByUploadObjectId(objId);
    uploadURLRepository.deleteByUploadObjectId(objId);
    this.clearChannelCache();
  }

  /**
   * 移除缓存中的通道信息
   */
  public void clearChannelCache() {
    List<UploadFileChannel> uploadFileChannelList = this.get();
    Cache cache = ehCacheCacheManager.getCacheManager().getCache("searchablecache");
    for (UploadFileChannel uploadFileChannel : uploadFileChannelList) {
      cache.remove("ufc" + uploadFileChannel.getId());
    }
  }

  public List<UploadFileChannel> getByObjectId(Integer id) {
    List<UploadFileChannel> uploadFileChannelList = uploadFileChannelRepository.findAllByUploadObjectId(id);
    return uploadFileChannelList;
  }

  public UploadFileChannel getById(Integer id) {
    Optional<UploadFileChannel> channel = uploadFileChannelRepository.findById(id);
    return channel.get();
  }

  /**
   * 查询通道信息
   *
   * @return 通道信息
   */
  public List<UploadFileChannel> get() {
    Cache cache = ehCacheCacheManager.getCacheManager().getCache("searchablecache");
    Query query = cache.createQuery();
    //查询结果中包含Key和value
    query.includeKeys().includeValues();
    Attribute<String> keyName = cache.getSearchAttribute("key");
    query.addCriteria(keyName.ilike("*ufc*"));
    Results results = query.execute();
    List<Result> resultList = results.all();

    List<UploadFileChannel> list = new ArrayList();
    if (resultList != null && !resultList.isEmpty()) {
      for (Result result : resultList) {
        UploadFileChannel e = (UploadFileChannel) result.getValue();
        list.add(e);
      }
      results.discard();
    } else {
      //查询数据库
      list = uploadFileChannelRepository.findAll();
      for (UploadFileChannel uploadFileChannel : list) {
        //将结果存入缓存
        cache.put(new Element("ufc" + uploadFileChannel.getId(), uploadFileChannel));
      }
    }
    return list;
  }

  /**
   * 开启102所有服务端
   */
  public synchronized void startAllChannel() {
    List<UploadFileChannel> uploadFileChannels = get();
    // 取通道状态正常并且是102s的类型
    List<UploadFileChannel> useChannelList = uploadFileChannels.stream().filter(s -> s.getChannelStatusEnum().equals(ChannelStatusEnum.E1)).collect(Collectors.toList());
    for (UploadFileChannel u : useChannelList) {
      // 获取上报对象协议类型
      List<UploadObject> uploadObjectList = uploadObjectService.get();
      UploadObject uploadObject = uploadObjectList.stream().filter(s -> s.getId().equals(u.getUploadObjectId())).collect(Collectors.toList()).get(0);

      if (!"ftp".equals(uploadObject.getUploadProtocolEnum().getCode()) && !"sftp".equals(uploadObject.getUploadProtocolEnum().getCode())) {
        // 创建通道对应的日志
        Logger logger = appenderFactory.getLogger(uploadObject.getUploadObjectName(), uploadObject.getUploadProtocolEnum().getMessage(), uploadObject.getObjectNo());
        if (FileConstant.nettyInstanceMap.get(u.getId()) != null) {
          FileConstant.nettyInstanceMap.remove(u.getId());
        }

        if ("102s".equals(uploadObject.getUploadProtocolEnum().getCode())) {
          if (FileConstant.nettyInstanceMap.get(u.getLocalIp() + ":" + u.getLocalPort()) == null) {
            // 创建netty服务
            UploadFileNettyServer uploadFileNettyServer = new UploadFileNettyServer(new InetSocketAddress(u.getLocalIp(), Integer.parseInt(u.getLocalPort())), Integer.parseInt(readerIdleTime));
            log.info(u.getChannelName()+"准备开启102服务.....");
            // 开启102服务端
            uploadFileNettyServer.start();
            // 将netty服务端实例保存到缓存变量，用于关闭通道时用。
            FileConstant.nettyInstanceMap.put(u.getLocalIp() + ":" + u.getLocalPort(), uploadFileNettyServer);
          }
        }
      }
    }
  }
}
