package com.priusis.controller;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.priusis.cache.InstalledProgramCache;
import com.priusis.lib.R;
import com.priusis.util.SysConfigUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.ini4j.ConfigParser;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import oshi.hardware.NetworkIF;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @author yangli
 * @since 2021/09/16
 */
@Slf4j
@Validated
@RestController
@RequestMapping(value = "remote_control")
public class RemoteControlController {


    @Value(value = "${vnc-repeater}")
    private String vncRepeater;

    @Value(value = "${apq.iot-gateway}")
    private String gateway;

    @Value(value = "${apq.url.device_info}")
    private String deviceInfoUrl;

    @Value(value = "${apq.url.send-control-req}")
    private String sendControlReqUrl;

    @Resource
    private InstalledProgramCache installedProgramCache;

    /**
     * 前端定时任务查询远程控制请求，不为空则表示有请求，展示确认弹窗
     */
    @GetMapping(value = "get_control_request")
    public R<Boolean> getControlRequest() throws IOException {
        return R.success(Convert.toBool(SysConfigUtil.getProperty("control.request"), false));
    }

    /**
     * 接受远程控制请求
     */
    @GetMapping(value = "accept_request")
    public R<Void> acceptRequest(@RequestParam @NotNull Long minutes)
            throws IOException, ConfigParser.DuplicateSectionException, ConfigParser.NoSectionException {
        Boolean hasRequest = Convert.toBool(SysConfigUtil.saveProperty("control.request", "0"), false);
        if (!hasRequest) return R.error("无远程请求");
        return startVncServer(minutes);
    }

    private R<Void> startVncServer(long minutes)
            throws IOException, ConfigParser.DuplicateSectionException, ConfigParser.NoSectionException {
        // 查询设备的远程ID
        String remoteId = getRemoteId();
        if (StrUtil.isBlank(remoteId)) return R.error("未查询到设备的远程ID");
        // 设置远程ID
        String path = installedProgramCache.getPrograms().stream()
                .filter(m -> "UltraVNC".equalsIgnoreCase(m.get("name")))
                .findFirst()
                .map(m -> m.get("path"))
                .orElse(null);
        if (StrUtil.isBlank(path)) return R.error("未检测到UltraVNC，请先安装");
        File file = new File(path + "ultravnc.ini");
        ConfigParser configParser = new ConfigParser();
        configParser.read(file);
        if (!configParser.hasSection("admin")) configParser.addSection("admin");
        configParser.set("admin", "service_commandline",
                StrUtil.format("-autoreconnect ID:{} -connect {} -run", remoteId, vncRepeater));
        configParser.write(file);

        // 重启VNC Server服务
        Runtime.getRuntime().exec("cmd /c net stop uvnc_service");
        Runtime.getRuntime().exec("cmd /c net start uvnc_service");

        // 定时任务，指定分钟后执行一次
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @SneakyThrows
            @Override
            public void run() {
                // 停止VNC Server服务
                Runtime.getRuntime().exec("cmd /c net stop uvnc_service");
                timer.cancel();
            }
        }, minutes * 60 * 1000);
        return R.success();
    }


    /**
     * 拒绝远程控制请求
     */
    @GetMapping(value = "refuse_request")
    public R<Void> refuseRequest() throws IOException {
        SysConfigUtil.saveProperty("control.request", "0");
        return R.success();
    }

    @GetMapping(value = "send_request")
    public R<Void> sendRequest(@RequestParam @NotNull Long minutes)
            throws IOException, ConfigParser.DuplicateSectionException, ConfigParser.NoSectionException {
        JSONObject rsp = JSONUtil.parseObj(HttpUtil.post(gateway + sendControlReqUrl,
                JSONUtil.createObj().set("minutes", minutes).set("macAddress", getMacAddress()).toString()));
        if (ObjectUtil.notEqual(rsp.getInt("code"), 0)) return R.error(rsp.getStr("msg"));
        startVncServer(minutes);
        return R.success();
    }


    private String getMacAddress() throws UnknownHostException, SocketException {
        NetworkIF networkIF = new NetworkIF();
        networkIF.setNetworkInterface(NetworkInterface.getByInetAddress(InetAddress.getLocalHost()));
        return networkIF.getMacaddr();
    }

    private String remoteId;

    private String getRemoteId() throws SocketException, UnknownHostException {
        if (StrUtil.isNotBlank(remoteId)) return remoteId;
        String mac = getMacAddress();
        JSONObject rsp = JSONUtil.parseObj(HttpUtil.get(gateway + StrUtil.format(deviceInfoUrl, mac)));
        if (ObjectUtil.notEqual(rsp.getInt("code"), 0)) {
            log.warn("查询设备信息失败, msg: {}", rsp.getStr("msg"));
            return null;
        }
        return remoteId = rsp.getJSONObject("data").getStr("remoteId");
    }
}
