package net.northking.cctp.se.lifecycle;

import com.alibaba.fastjson.JSON;
import com.sun.management.OperatingSystemMXBean;
import net.northking.cctp.se.config.AtuServerConfig;
import net.northking.cctp.se.dto.ScriptEngineInfo;
import net.northking.cctp.se.lifecycle.entity.CdEngineInfo;
import net.northking.cctp.se.lifecycle.entity.CdEngineInfoRegisterDto;
import net.northking.cctp.se.lifecycle.entity.CdEngineInfoResultDto;
import net.northking.cctp.se.lifecycle.entity.CdPcDevice;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

/**
 * 引擎启动注册
 */
@Component
public class EngineRegisterService {
    private static final Logger logger = LoggerFactory.getLogger(EngineRegisterService.class);

    @Autowired
    private AtuServerConfig atuServerConfig;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Value("${server.port}")
    private String port;

    @Value("${atu.server.engineSys}")
    private String engineSys;

    private static final String localhostIp = "127.0.0.1";
    /**
     * 启动时注册至平台设备管理
     * @return 设备ID
     */
    public CdEngineInfoResultDto register(ScriptEngineInfo engineInfo){
        int num = 1;
        boolean status = false;
        CdEngineInfoResultDto registerInfo = new CdEngineInfoResultDto();
        logger.info("引擎信息   获取----------------");
        CdEngineInfoRegisterDto dto = new CdEngineInfoRegisterDto();
        try {
            if("windows".equals(engineSys)){//PC端
                //获取并组装引擎信息
                setEngInfo(dto);
                //获取并组装pc机器信息
                setPcInfo(dto,engineInfo);
            }
            if("linux".equals(engineSys)){ //linux执行机
                setEngInfoLinux(dto);
                //获取并组装pc机器信息
                setPcInfoLinux(dto,engineInfo);
            }
            if (dto.getCdPcDevice() != null && dto.getCdPcDevice().getIpAddr() != null) {
                engineInfo.setIpAddress(dto.getCdPcDevice().getIpAddr());
            }
        }catch (Exception e){
            logger.info("获取引擎信息报错，停止注册----------", e);
            throw new RuntimeException("停止注册");
        }
        logger.info("引擎信息打印:"+ JSON.toJSONString(dto));
        String url = atuServerConfig.getServerUrl()+atuServerConfig.getEngineRegister();
        while (!status){
            logger.info("引擎注册  第{}次 开始------",num);
            try {
                ResponseEntity<CdEngineInfoResultDto> result = restTemplate.postForEntity(url,dto, CdEngineInfoResultDto.class);
                if(HttpStatus.OK.equals(result.getStatusCode())){
                    status=true;//注册成功
                }
                registerInfo=result.getBody();
            }catch (Exception e){
                logger.info("失败原因-----------"+e.getMessage());
            }
            logger.info("引擎注册  第{}次 结果------{}",num,status?"成功":"失败");
            if(!status){
                try {
                    logger.info("引擎注册  第{}次 等待30s--------------",num);
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    logger.error("",e);
                }
            }
            num++;
        }
        logger.info("引擎注册   结束------");
        return registerInfo;
    }

    private void setPcInfoLinux(CdEngineInfoRegisterDto dto, ScriptEngineInfo engineInfo) throws Exception{
        CdPcDevice pcInfo = new CdPcDevice();
        pcInfo.setDeviceName(InetAddress.getLocalHost().getHostName());
        pcInfo.setDomainName("设备域名");
        pcInfo.setIpAddr(getLinuxIp());
        pcInfo.setOsArch(System.getProperty("os.arch"));
        pcInfo.setOsName(System.getProperty("os.name"));
        pcInfo.setRamSize(getMemory());
        dto.setCdPcDevice(pcInfo);
        if (!StringUtils.isBlank(atuServerConfig.getRemoteProtocol())) {
            pcInfo.setRemoteProtocol(atuServerConfig.getRemoteProtocol());
        }
        if (!StringUtils.isBlank(atuServerConfig.getRemotePort())) {
            pcInfo.setRemotePort(atuServerConfig.getRemotePort());
        }
        engineInfo.setOsName(pcInfo.getOsName());
    }

    private void setEngInfoLinux(CdEngineInfoRegisterDto dto) {
        CdEngineInfo engInfo = new CdEngineInfo();
        engInfo.setEngineName(atuServerConfig.getEngineName());
        engInfo.setIpAddr(getLinuxIp());
        engInfo.setIpPort(port);
        engInfo.setRunningRelease(atuServerConfig.getEngineVersion());
        engInfo.setEngineDesc("引擎描述");
        engInfo.setIsPcExecutor(atuServerConfig.getIsPcExecutor());
        dto.setCdEngineInfo(engInfo);
    }


    /**
     * 设置引擎信息
     * @param dto
     */
    private void setEngInfo(CdEngineInfoRegisterDto dto) throws Exception {
        CdEngineInfo engInfo = new CdEngineInfo();
        engInfo.setEngineName(atuServerConfig.getEngineName());
        engInfo.setIpAddr(getWindowsAddress());
        engInfo.setIpPort(port);
        engInfo.setRunningRelease(atuServerConfig.getEngineVersion());
        engInfo.setEngineDesc("引擎描述");
        engInfo.setIsPcExecutor(atuServerConfig.getIsPcExecutor());
        dto.setCdEngineInfo(engInfo);
    }

    /**
     * 设置pc机器信息
     * @param dto
     */
    private void setPcInfo(CdEngineInfoRegisterDto dto,ScriptEngineInfo engineInfo)throws Exception {
        CdPcDevice pcInfo = new CdPcDevice();
        pcInfo.setDeviceName(InetAddress.getLocalHost().getHostName());
        pcInfo.setDomainName("设备域名");
        pcInfo.setIpAddr(getWindowsAddress());
        pcInfo.setMacAddr(getMacAddress());
        pcInfo.setOsArch(System.getProperty("os.arch"));
        pcInfo.setOsName(System.getProperty("os.name"));
        pcInfo.setRamSize(getMemory());
        if (!StringUtils.isBlank(atuServerConfig.getRemoteProtocol())) {
            pcInfo.setRemoteProtocol(atuServerConfig.getRemoteProtocol());
        }
        if (!StringUtils.isBlank(atuServerConfig.getRemotePort())) {
            pcInfo.setRemotePort(atuServerConfig.getRemotePort());
        }
        dto.setCdPcDevice(pcInfo);
        engineInfo.setOsName(pcInfo.getOsName());
    }

    /**
     * 获取机器mac地址
     * @return
     * @throws Exception
     */
    private String getMacAddress() throws Exception {
        byte[] macByte = NetworkInterface.getByInetAddress(InetAddress.getLocalHost()).getHardwareAddress();
        StringBuilder sb = new StringBuilder();
        for (byte b : macByte) {
            sb.append("-");
            //吧byte转化为正整数
            String num = Integer.toHexString(b & 0xFF);
            sb.append(num.length()==1?0+num:num);
        }
        return sb.toString().toUpperCase().substring(1);
    }

    /**
     * 获取机器内存大小
     * @return
     */
    private String getMemory(){
        OperatingSystemMXBean mx = (OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
        int mb = 1024*1024;
        return (mx.getTotalPhysicalMemorySize() / mb)+"M";
    }

    private String getLinuxIp(){
        String ip = localhostIp;
        try {
            for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();en.hasMoreElements();){
                NetworkInterface intf = en.nextElement();
                String name = intf.getName();
                if(!name.contains("docker") && !name.contains("lo")){
                    for (Enumeration<InetAddress> ipAddr = intf.getInetAddresses();ipAddr.hasMoreElements();){
                        InetAddress add = ipAddr.nextElement();
                        if (!add.isLoopbackAddress()) {
                            String address = add.getHostAddress().toString();
                            if(!address.contains("::") && ! address.contains("0:0:") && !address.contains("fe80")){
                                ip=address;
                            }
                        }
                    }
                }
            }
        }catch (Exception e){
            logger.error("======linuxIP地址获取失败:",e);
        }
        logger.info("执行引擎ip -> {}", ip);
        return ip;
    }

    private String getWindowsAddress() {
        InetAddress candidateAddress = null;
        try {
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
            while (networkInterfaces.hasMoreElements()) {
                NetworkInterface iface = networkInterfaces.nextElement();
                for (Enumeration<InetAddress> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) {
                    InetAddress inetAddr = inetAddrs.nextElement();
                    if (!inetAddr.isLoopbackAddress()) {
                        if (inetAddr.isSiteLocalAddress()) {
                            candidateAddress = inetAddr;
                        }
                        if (candidateAddress == null) {
                            candidateAddress = inetAddr;
                        }

                    }
                }
            }

            if (candidateAddress==null) {
                candidateAddress = InetAddress.getLocalHost();
            }
        } catch (Exception e) {
            logger.error("",e);
        }
        String hostAddress = null;
        if (candidateAddress != null) {
            hostAddress = candidateAddress.getHostAddress();
        }
        return hostAddress;
    }

}
