package top.octopusyan.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jfoenix.controls.*;
import com.jfoenix.validation.base.ValidatorBase;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import top.octopusyan.base.BaseController;
import top.octopusyan.config.ProxyConfig;
import top.octopusyan.config.ProxyConfig.ProxyServer;
import top.octopusyan.config.ProxyConfig.ProxyType;
import top.octopusyan.config.TextValidate;
import top.octopusyan.http.listener.OnHttpListener;
import top.octopusyan.manager.FrpManager;
import top.octopusyan.manager.ProxyManager;
import top.octopusyan.manager.http.request.ProxySetup;
import top.octopusyan.model.ApplicatonStore;
import top.octopusyan.model.ProxySetupModel;
import top.octopusyan.utils.*;
import top.octopusyan.view.ProxyListItemView;

import java.io.IOException;
import java.util.*;

import static top.octopusyan.model.ApplicatonStore.*;

/**
 * @author : octopus yan
 * @email : octopus_yan@foxmail.com
 * @description :
 * @create : 2022-4-4 22:32
 */
public class MainController extends BaseController<StackPane> implements Initializable {

    public static final String PROXY_LIST_ITEM_CLASS = "proxyListItem";
    public static final String PROXY_LIST_ITEM_SELECT_CLASS = "proxyListItem-select";


    /* 窗口通用控件 */
    public StackPane root;
    public JFXButton minimizeBtn, closeBtn;
    public Label appVersionLabel;

    /* 隧道设置控件 */
    public JFXComboBox<String> proxyServerComboBox;
    public JFXButton resetProxyBtn;
    public JFXTextField proxyNameTextField;
    public JFXRadioButton openProxyRBtn, closeProxyRBtn;
    public JFXComboBox<String> proxyProtocolComboBox;
    public JFXRadioButton serverProviderRBtn, serverVisitorRBtn;
    public Label localHostLabel;
    public JFXTextField localHostTextField, localPortTextField;
    public HBox domainPane;
    public JFXTextField domainTextField, domainSuffixTextField;
    public JFXButton customizeDomainBtn;
    public HBox httpUserPane;
    public JFXTextField httpUserTextField;
    public HBox httpPwdPane;
    public JFXTextField httpPwdTextField;
    public HBox p2pRolePane, p2pPwdPane, p2pRoleView, serverNamePane;
    public JFXButton copyP2pConfig, importP2pConfig;
    public JFXTextField p2pPwdTextField, serverNameTextField;
    public JFXButton proxyStatusTip, httpUserTip, proxyTypeTip, p2pPwdTip, serverNameTip;
    public HBox proxyStatusPane;
    public Label runingLabel;
    public Hyperlink domainLink;
    public JFXButton copyDomainBtn;

    /* 隧道列表控件 */
    public JFXListView<ProxyListItemView> proxyListView;
    public JFXButton addProxyBtn;

    /* 日志帮助面板控件 */
    public JFXTabPane tabPane;
    public Tab proxyLogPane;
    public JFXButton clearLogBtn;

    /* 功能控件 */
    public JFXButton startProxyBtn, logoutBtn;

    /* 自定义属性 */
    private ObservableList<Node> children;
    private final ProxySetupModel proxySetupModel = new ProxySetupModel(ProxyManager.initProxy(null));
    private final BooleanProperty customizeDomain = new SimpleBooleanProperty(false);
    private final Map<String, ProxySetup> userProxy = new HashMap<>();
    private final Map<String, FrpManager> frpUtilMap = new HashMap<>();
    private final ToggleGroup openProxyGroup = new ToggleGroup();
    private final ToggleGroup serverRoleGroup = new ToggleGroup();
    private final SimpleBooleanProperty setup = new SimpleBooleanProperty(false);

    @Override
    public boolean dragWindow() {
        return true;
    }

    @Override
    public StackPane getRootPanel() {
        return root;
    }

    @NotNull
    @Override
    public String getRootFxmlPath() {
        return "/fxml/main.fxml";
    }

    @Override
    public Label getAppVersionLabel() {
        return appVersionLabel;
    }

    @Override
    public Button getClooseBtn() {
        return closeBtn;
    }

    @Override
    public Button getMinimizeBtn() {
        return minimizeBtn;
    }

    @Override
    public JFXButton getFirstBtn() {
        return minimizeBtn;
    }

    @Override
    public void initData() {
        // 初始化用户隧道列表
        setProxyList(Collections.singletonList(proxySetupModel.get()));
        // 重置隧道列表视图
        initProxyListView();

        // 初始化隧道类型
        Arrays.asList(ProxyType.values()).forEach((type) -> proxyProtocolComboBox.getItems().add(type.name()));

        // 初始化服务器
        Arrays.asList(ProxyServer.values()).forEach((server) -> proxyServerComboBox.getItems().add(server.getServerName()));

        // 获取用户隧道列表
        ProxyManager.getList(new OnHttpListener<List<ProxySetup>>() {
            @Override
            public void onSucceed(List<ProxySetup> result) {

                Platform.runLater(() -> {

                    // 如果用户隧道列表不为空
                    if (result != null && result.size() > 0) {

                        // 上次关闭时选择的隧道
                        if (selectProxyName != null)
                            for (int i = 0; i < result.size(); i++) {
                                if (result.get(i).getProxy_name().equals(selectProxyName))
                                    selectProxy(i);
                                selectProxyName = null;
                            }

                        // 保存用户隧道信息
                        for (ProxySetup setup : result) {
                            userProxy.put(setup.getId().toString(), setup);
                        }

                        proxySetupModel.set(result.get(selectProxy()));
                        // 初始化用户隧道列表
                        setProxyList(result);
                        // 重置隧道列表视图
                        initProxyListView();
                    }

                });
            }

            @Override
            public void onFail(Exception e) {

            }
        });

        /* 数据绑定 */

        // 服务器
        proxyServerComboBox.valueProperty().bindBidirectional(proxySetupModel.serverProperty());
        // 隧道名称
        proxyNameTextField.textProperty().bindBidirectional(proxySetupModel.proxyNameProperty());
        // 隧道类型
        proxyProtocolComboBox.valueProperty().bindBidirectional(proxySetupModel.proxyTypeProperty());
        // 内网地址
        localHostTextField.textProperty().bindBidirectional(proxySetupModel.localIpProperty());
        // 内网端口
        localPortTextField.textProperty().bindBidirectional(proxySetupModel.localPortProperty());
        // 外网访问子域名
        domainTextField.textProperty().bindBidirectional(proxySetupModel.domainProperty());
        // 外网访问主域名
        domainSuffixTextField.textProperty().bindBidirectional(proxySetupModel.domainSuffixProperty());
        // 是否自定义访问域名
        customizeDomain.bindBidirectional(proxySetupModel.isCustomizeProperty());
        // http访问用户名
        httpUserTextField.textProperty().bindBidirectional(proxySetupModel.httpUserProperty());
        // http访问密码
        httpPwdTextField.textProperty().bindBidirectional(proxySetupModel.httpPwdProperty());
        // p2p访问密码
        p2pPwdTextField.textProperty().bindBidirectional(proxySetupModel.skProperty());
        // p2p访问服务提示
        serverNameTextField.textProperty().bindBidirectional(proxySetupModel.serverNameProperty());
        // 启动成功提示
        proxyStatusPane.visibleProperty().bindBidirectional(proxySetupModel.runningProperty());
    }

    @Override
    public void initViewStyle() {
        children = ((Pane) domainPane.getParent()).getChildren();

        // 默认隧道协议为http
        children.remove(p2pRolePane);
        children.remove(p2pPwdPane);
        children.remove(serverNamePane);

        // 设置列表
        proxyListView.getSelectionModel().select(0);
        // 启用链接
        openProxyRBtn.setToggleGroup(openProxyGroup);
        closeProxyRBtn.setToggleGroup(openProxyGroup);
        openProxyRBtn.setUserData(true);
        closeProxyRBtn.setUserData(false);
        openProxyRBtn.setSelected(true);

        // 点对点服务角色
        serverProviderRBtn.setToggleGroup(serverRoleGroup);
        serverVisitorRBtn.setToggleGroup(serverRoleGroup);
        serverProviderRBtn.setUserData(true);
        serverVisitorRBtn.setUserData(false);
        serverProviderRBtn.setSelected(true);

        // 是否启用
        proxySetupModel.statusProperty().addListener((observable, oldValue, newValue) -> {
            openProxyRBtn.setSelected(newValue);
            closeProxyRBtn.setSelected(!newValue);
            closeProxy(!newValue);
        });

        // 隧道类型监听
        proxySetupModel.proxyTypeProperty().addListener((observable, oldValue, newValue) -> {
            String newType = StringUtils.lowerCase(newValue);
            String port, host;
            if (proxySetupModel.getId() == null ||
                    !newType.equals(StringUtils.upperCase(userProxy.get(proxySetupModel.getId()).getProxy_type()))
            ) {
                host = "127.0.0.1";
                port = ProxyConfig.getTypePort(newType).toString();
            } else {
                host = proxySetupModel.getLocalIp();
                port = proxySetupModel.getLocalPort();
            }
            // 隧道类型相关控件显示
            boolean isHttp = ProxyConfig.isHttp(proxySetupModel);
            boolean isP2p = ProxyConfig.isP2p(proxySetupModel);
            if (isHttp) {
                // http / https
                children.remove(p2pRolePane);
                children.remove(p2pPwdPane);
                children.remove(serverNamePane);
                if (!children.contains(domainPane)) {
                    int index = children.size() - 1;
                    children.add(index, httpPwdPane);
                    children.add(index, httpUserPane);
                    children.add(index, domainPane);
                }
                // 添加验证
                ObservableList<ValidatorBase> httpValid = domainTextField.getValidators();
                if (!httpValid.contains(TextValidate.DomainRequired)) {
                    httpValid.add(TextValidate.DomainRequired);// 域名为空检查
                    httpValid.add(TextValidate.domainFormatValidator(proxySetupModel));// 域名格式检查
                    httpValid.add(TextValidate.domainLengthValidator(proxySetupModel));// 域名长度检查
                    httpValid.add(TextValidate.domainAddressValidator(proxySetupModel));// 自定义域名解析检查
                }
                p2pPwdTextField.getValidators().clear();
                // 默认系统分配域名
                ProxySetup proxySetup = proxySetupModel.get();
                if (proxySetup.getDomain().equals("")) {
                    proxySetup.setDomain("." + ProxyConfig.getServerPath(proxySetupModel.getServer()));
                    proxySetupModel.set(proxySetup);
                }
            } else if (isP2p) {
                // stcp / xtcp
                children.remove(httpPwdPane);
                children.remove(httpUserPane);
                children.remove(domainPane);
                int index = children.size() - 1;
                if (!children.contains(p2pRolePane)) {
                    children.add(index, p2pPwdPane);
                    children.add(index - 1, p2pRolePane);
                    if (proxySetupModel.isProvider != null && !proxySetupModel.isProvider) {
                        children.add(index, serverNamePane);
                    }
                }
                Boolean provider = proxySetupModel.isProvider();
                importP2pConfig.setVisible(provider != null && !provider);
                copyP2pConfig.setVisible(provider == null || provider);
                // 添加验证
                ObservableList<ValidatorBase> p2pValid = p2pPwdTextField.getValidators();
                if (!p2pValid.contains(TextValidate.p2pPwdRequired)) {
                    p2pValid.add(TextValidate.p2pPwdRequired);
                    p2pValid.add(TextValidate.p2pServerNameRequired);
                }
                serverNameTextField.textProperty().set("提供者");
                domainTextField.getValidators().clear();
            } else {
                // tcp / udp
                children.remove(p2pRolePane);
                children.remove(p2pPwdPane);
                children.remove(serverNamePane);
                children.remove(httpPwdPane);
                children.remove(httpUserPane);
                children.remove(domainPane);

                // 验证
                p2pPwdTextField.getValidators().clear();
                domainTextField.getValidators().clear();
            }

            // 设置本地端口
            localHostTextField.setText(host);
            localPortTextField.setText(port);
        });

        // 服务角色监听
        proxySetupModel.serverNameProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue == null) {
                serverProviderRBtn.setSelected(false);
                serverVisitorRBtn.setSelected(false);
                proxySetupModel.isProvider = null;
                return;
            }

            boolean isProvider = newValue.equals("提供者");
            serverProviderRBtn.setSelected(isProvider);
            serverVisitorRBtn.setSelected(!isProvider);
            proxySetupModel.isProvider = isProvider;
        });
        serverRoleGroup.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue == null) return;
            proxySetupModel.isProvider = (boolean) newValue.getUserData();
            if (proxySetupModel.isProvider) {
                localHostLabel.setText("内网服务地址");
                localHostTextField.setPromptText("内网服务IP (IPv4)");
                localPortTextField.setPromptText("端口");
                copyP2pConfig.setVisible(true);
                importP2pConfig.setVisible(false);
                children.remove(serverNamePane);
                proxySetupModel.setServerName("提供者");
            } else {
                localHostLabel.setText("服务绑定地址");
                localHostTextField.setPromptText("服务绑定IP (IPv4)");
                localPortTextField.setPromptText("端口");
                copyP2pConfig.setVisible(false);
                importP2pConfig.setVisible(true);
                if (!children.contains(serverNamePane)) children.add(children.size() - 3, serverNamePane);
                String serverName = proxySetupModel.getServerName();
                proxySetupModel.setServerName("提供者".equals(serverName) ? "" : serverName);
            }
            ObservableList<Node> children = p2pRolePane.getChildren();
            JFXButton remove = proxySetupModel.isProvider ? importP2pConfig : copyP2pConfig;
            JFXButton add = proxySetupModel.isProvider ? copyP2pConfig : importP2pConfig;
            if (children.contains(add)) children.add(add);
            children.remove(remove);
        });

        // 隧道名称
        proxySetupModel.proxyNameProperty().addListener((observable, oldValue, newValue) -> {
            if (proxyListView.getItems().size() > 0)
                proxyListView.getItems().get(selectProxy()).setName(newValue);
        });

        // 运行状态监听
        proxySetupModel.runningProperty().addListener((observable, oldValue, newValue) -> {
            String startClass = "startProxyBtn";
            String stopClass = "stopProxyBtn";
            // 启动按钮
            startProxyBtn.getStyleClass().remove(startClass);
            startProxyBtn.getStyleClass().remove(stopClass);
            startProxyBtn.getStyleClass().add(newValue ? stopClass : startClass);
            startProxyBtn.setText(newValue ? "停止" : "启动");
            // 列表显示
            ProxyListItemView itemView = proxyListView.getItems().get(selectProxy());
            itemView.setStatus(newValue);
            setDomainLink();
        });

        // 外网访问地址
        customizeDomain.addListener((observable, oldValue, newValue) -> {
            AnchorPane parent = (AnchorPane) domainTextField.getParent();
            if (newValue) {
                // 隐藏系统域名
                parent.getChildren().remove(domainSuffixTextField);
                domainTextField.promptTextProperty().set("自定义域名");
                customizeDomainBtn.setText("系统分配");
            } else {
                // 显示系统域名
                if (!parent.getChildren().contains(domainSuffixTextField))
                    parent.getChildren().add(domainSuffixTextField);
                domainTextField.promptTextProperty().set("自定义子域名 大于3位");
                customizeDomainBtn.setText("自定义");
            }
        });

        // 默认展示 "常见问题" 面板
        tabPane.getSelectionModel().select(1);
    }

    /**
     * 设置访问链接
     */
    private void setDomainLink() {
        domainLink.setVisible(true);
        copyDomainBtn.setVisible(true);
        // 外网访问连接
        if (ProxyConfig.isHttp(proxySetupModel)) {
            runingLabel.setText("启动成功！立即访问 ");
            // http / https
            String prefix = proxySetupModel.getProxyType() + "://";
            domainLink.textProperty().set(prefix + proxySetupModel.getDomain() + proxySetupModel.getDomainSuffix());
        } else if (ProxyConfig.isP2p(proxySetupModel)) {
            // stcp / xtcp
            runingLabel.setText("启动成功！");
            domainLink.setText("");
            domainLink.setVisible(false);
            copyDomainBtn.setVisible(false);
        } else {
            // ssh / tcp
            domainLink.textProperty().set(
                    ProxyConfig.getServerIP(proxySetupModel.getServer()) + ":" + proxySetupModel.getRemotePort()
            );
        }
    }

    @Override
    public void initViewAction() {
        // 重置
        resetProxyBtn.setOnMouseClicked(event -> {
            ProxySetup proxySetup = userProxy.get(proxySetupModel.getId());
            if (proxySetup != null) {
                proxySetup.setRuning(proxySetupModel.isRunning());
                proxySetupModel.set(proxySetup);
                domainTextField.resetValidation();
            }
        });

        // 日志清理
        clearLogBtn.setOnMouseClicked(event -> {
            ProxySetup proxySetup = userProxy.get(proxySetupModel.getId());
            if (proxySetup != null && frpUtilMap.get(proxySetup.getId().toString()) != null)
                frpUtilMap.get(proxySetup.getId().toString()).clearLog();
        });

        // 更换服务器地址
        proxyServerComboBox.valueProperty().addListener((observable, oldValue, newValue) -> {
            // 重新设置是否自定义
            boolean customize = DomainUtil.isCustomize(proxySetupModel.get());
            if (!DomainUtil.isCustomize(proxySetupModel.get(), oldValue) || !customize) {
                proxySetupModel.setDomainSuffix("." + ProxyConfig.getServerPath(newValue));
                customizeDomain.set(false);
            } else {
                proxySetupModel.setDomainSuffix("");
                // 域名检查
                domainTextField.validate();
                customizeDomain.set(true);
            }
        });

        // 是否启用
        openProxyGroup.selectedToggleProperty().addListener(
                (ObservableValue<? extends Toggle> ov, Toggle old_toggle, Toggle new_toggle) -> {
                    Toggle toggle = openProxyGroup.getSelectedToggle();
                    if (toggle != null) {
                        // 设置状态
                        proxySetupModel.setStatus((Boolean) toggle.getUserData());
                    }
                }
        );

        // 自定义访问域名
        customizeDomainBtn.setOnMouseClicked((event) -> {
            // 是否切换为自定义域名
            if (!customizeDomain.get()) {
                // 用户域名是否自定义
                if (!DomainUtil.isCustomize(proxySetupModel.get())) {
                    proxySetupModel.setDomain("");
                } else {
                    proxySetupModel.setDomain(proxySetupModel.getDomain());
                }
                proxySetupModel.setDomainSuffix("");
            } else {
                // 用户域名是否自定义
                if (DomainUtil.isCustomize(proxySetupModel.get())) {
                    proxySetupModel.setDomain("");
                    proxySetupModel.setDomainSuffix("." + ProxyConfig.getServerPath(proxySetupModel.getServer()));
                } else {
                    proxySetupModel.setDomain(DomainUtil.getCustomize(proxySetupModel.get()));
                    proxySetupModel.setDomainSuffix(DomainUtil.getSuffix(userProxy.get(proxySetupModel.getId())));
                }
            }
            customizeDomain.set(!customizeDomain.get());
        });

        // 本地IP检查
        localHostTextField.getValidators().add(TextValidate.IpRequired);
        localHostTextField.getValidators().add(TextValidate.IpFormat);
        localHostTextField.textProperty().addListener((observable, oldValue, newValue) -> localHostTextField.validate());

        // 端口检查
        localPortTextField.getValidators().add(TextValidate.PortRequired);
        localPortTextField.getValidators().add(TextValidate.PortFormat);
        localPortTextField.textProperty().addListener((observable, oldValue, newValue) -> localPortTextField.validate());

        // 域名检查
        setup.addListener((observable, oldValue, newValue) -> {
            if (newValue) domainTextField.validate();
            if (newValue) p2pPwdTextField.validate();
        });

        // 复制服务设置
        copyP2pConfig.setOnMouseClicked(event -> {
            if (!localPortTextField.validate() || !localPortTextField.validate() || !p2pPwdTextField.validate())
                return;

            ProxySetup setup = proxySetupModel.get();
            // 整理服务设置
            String serverName = getAccount() + "_" + setup.getSort();
            setup.setServer_name(ApplicatonStore.getUserToken() + "." + EncryptionUtil.MD5_16(serverName));
            setup.setId(null);
            setup.setRuning(false);
            setup.setSort(null);
            setup.setStatus(null);
            JSONObject json = JSON.parseObject(JSON.toJSONString(setup));

            try {
                String serverConfig = EncryptionUtil.DESencode(json.toJSONString(), EncryptionUtil.getDefaultPassword());
                // 设置剪切板
                ClipUtil.setClip(FrpManager.serverConfigHeader + serverConfig);
                AlertUtil.info("复制成功").show();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        // 导入设置
        importP2pConfig.setOnMouseClicked(event -> {
            try {
                String clipData = ClipUtil.getString();
                // 服务设置检验
                if (clipData == null || !clipData.contains(FrpManager.serverConfigHeader)) throw new Exception();
                // 解密服务设置
                clipData = clipData.replace(FrpManager.serverConfigHeader, "");
                String jsonStr = EncryptionUtil.DESdecode(clipData, EncryptionUtil.getDefaultPassword());
                JSONObject jsonObject = JSON.parseObject(jsonStr);
                ProxySetup setup = jsonObject.toJavaObject(ProxySetup.class);
                setup.setId(proxySetupModel.getId() == null ? null : Integer.parseInt(proxySetupModel.getId()));
                setup.setSort(proxySetupModel.getSort());
                setup.setRuning(proxySetupModel.isRunning());
                setup.setStatus(proxySetupModel.getStatus());
                proxySetupModel.set(setup);
                AlertUtil.info("导入成功").show();
            } catch (Exception e) {
                AlertUtil.error("导入失败，请重新复制服务设置").show();
            }
        });

        // 添加验证
        ObservableList<ValidatorBase> httpValid = domainTextField.getValidators();
        httpValid.add(TextValidate.DomainRequired);// 域名为空检查
        httpValid.add(TextValidate.domainFormatValidator(proxySetupModel));// 域名格式检查
        httpValid.add(TextValidate.domainLengthValidator(proxySetupModel));// 域名长度检查
        httpValid.add(TextValidate.domainAddressValidator(proxySetupModel));// 自定义域名解析检查
        domainTextField.textProperty().addListener((observable, oldValue, newValue) -> domainTextField.validate());
        p2pPwdTextField.textProperty().addListener((observable, oldValue, newValue) -> p2pPwdTextField.validate());

        // 访问密码检查
        p2pPwdTextField.textProperty().addListener((observable, oldValue, newValue) -> {
            if (!p2pPwdTextField.getValidators().contains(TextValidate.p2pPwdRequired)) {
                p2pPwdTextField.getValidators().add(TextValidate.p2pPwdRequired);   // 访问密码为空检查
                p2pPwdTextField.getValidators().add(TextValidate.HttpPwdFormat);    // 访问密码格式检查
            } else
                p2pPwdTextField.validate();
        });

        // 点击隧道列表
        proxyListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
            ObservableList<ProxyListItemView> items = proxyListView.getItems();

            if (items.size() == 0) return;

            for (HBox item : items) {
                item.getStyleClass().remove(PROXY_LIST_ITEM_SELECT_CLASS);
            }
            if (newValue != null) {
                newValue.getStyleClass().add(PROXY_LIST_ITEM_SELECT_CLASS);
                int oldIndex = items.indexOf(oldValue);
                int newIndex = items.indexOf(newValue);
                // 保存隧道状态
                ObservableList<ProxySetup> proxyList = proxyList();
                if (oldIndex != -1 && StringUtils.isNotEmpty(proxyList.get(oldIndex).getProxy_name()))
                    proxyList.set(oldIndex, proxySetupModel.get());
                ProxySetup proxySetup = proxyList.get(newIndex);
                selectProxy(newIndex);
                Platform.runLater(() -> {
                    setup.set(false);
                    proxySetupModel.set(proxySetup);
                    // 设置日志面板
                    FrpManager frpManager = frpUtilMap.get(String.valueOf(proxySetup.getId()));
                    proxyLogPane.contentProperty().set(frpManager == null ? null : frpManager.getConsole());
                    setup.set(true);
                    setDomainLink();
                });
            }
        });

        // 添加隧道
        addProxyBtn.setOnMouseClicked(event -> {
            // 获取默认隧道设置加入列表
            ObservableList<ProxySetup> proxyList = proxyList();
            addProxyList(ProxyManager.initProxy(proxyList.get(proxyList.size() - 1).getSort()));
            // 重置隧道列表视图
            initProxyListView();
            proxyListView.getSelectionModel().select(proxyListView.getItems().size() - 1);
        });

        // 启动
        startProxyBtn.setOnMouseClicked(event -> {
            if (proxySetupModel.isRunning())
                stopProxy();
            else
                startProxy();
        });

        // 链接跳转
        domainLink.setOnMouseClicked(event -> getApplication().getHostServices().showDocument(domainLink.getText()));

        // 复制外网访问地址
        copyDomainBtn.setOnMouseClicked(event -> {
            // 设置剪切板
            ClipUtil.setClip(domainLink.getText());
            // 复制成功提示
            AlertUtil.info("复制成功，快去分享给小伙伴吧！").show();
        });

        // 退出登录
        logoutBtn.setOnMouseClicked(event -> {
            for (String key : frpUtilMap.keySet()) {
                frpUtilMap.get(key).stop();
            }
            ApplicatonStore.logout();
            try {
                jumpTo(new LoginController());
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        // 隧道类型提示
        proxyTypeTip.setOnMouseClicked(event -> {
            TooltipUtil util = getTooltipUtil();
            if (util.isShowing()) util.hide();
            else util.showProxyTypeTip(event);
        });
        // http访问用户名提示
        httpUserTip.setOnMouseClicked(event -> {
            TooltipUtil util = getTooltipUtil();
            if (util.isShowing()) util.hide();
            else util.showHttpUserTip(event);
        });
        // 隧道启用提示
        proxyStatusTip.setOnMouseClicked(event -> {
            TooltipUtil util = getTooltipUtil();
            if (util.isShowing()) util.hide();
            else util.showProxyStatusTip(event);
        });
        // p2p 访问密码提示
        p2pPwdTip.setOnMouseClicked(event -> {
            TooltipUtil util = getTooltipUtil();
            if (util.isShowing()) util.hide();
            else util.showP2pPwdTip(event);
        });
        // p2p 访问服务提示
        serverNameTip.setOnMouseClicked(event -> {
            TooltipUtil util = getTooltipUtil();
            if (util.isShowing()) util.hide();
            else util.showP2pServerName(event);
        });
    }

    /**
     * 是否启用当前隧道
     */
    private void closeProxy(boolean close) {
        if (close && proxySetupModel.isRunning()) stopProxy();

        proxyNameTextField.setDisable(close);   // 隧道名称
        proxyProtocolComboBox.setDisable(close);// 隧道类型
        localHostTextField.setDisable(close);   // 本地地址
        localPortTextField.setDisable(close);   // 本地端口
        domainTextField.setDisable(close);      // 外网子域名
        httpUserTextField.setDisable(close);    // 外网子域名
        httpPwdTextField.setDisable(close);     // 外网子域名
        startProxyBtn.setDisable(close);        // 启动按钮
        p2pRoleView.setDisable(close);          // p2p角色
        p2pPwdTextField.setDisable(close);      // p2p访问面板

        // 运行状态
        ProxyListItemView itemView = proxyListView.getItems().get(selectProxy());
        itemView.setStatus(close ? null : proxySetupModel.isRunning());

    }

    private void initProxyListView() {
        ObservableList<ProxySetup> proxyList = proxyList();
        for (ProxySetup proxy : proxyList.subList(proxyListView.getItems().size(), proxyList.size())) {
            setProxyListView(proxyList.indexOf(proxy), proxy);
        }
        // 设置选中
        proxyListView.getSelectionModel().select(selectProxy());
    }

    private void setProxyListView(int index, ProxySetup setup) {
        ObservableList<ProxyListItemView> items = proxyListView.getItems();
        // 是否添加
        boolean isNew = index >= items.size();
        ProxyListItemView itemView;
        if (isNew) {
            itemView = new ProxyListItemView();
            itemView.setName(setup.getProxy_name());
        } else {
            itemView = items.get(index);
        }
        // 运行状态
        itemView.setStatus(setup.isRuning());
        // 点击删除
        itemView.getDeleteBtn().setOnMouseClicked(event -> {
            if(items.size() == 1) {
                AlertUtil.error("最后一个连接不可删除！").show();
                return;
            }

            // 关闭连接
            if (proxyList().get(index).isRuning()) {
                frpUtilMap.get(String.valueOf(index)).stop();
            }
            // 调用删除接口
            if (setup.getId() != null) {
                ProxyManager.delete(setup.getId());
            }
        });
        // 是否选中
        if (selectProxy() == index) itemView.getStyleClass().add(PROXY_LIST_ITEM_SELECT_CLASS);
        // 添加
        if (isNew) items.add(index, itemView);
    }

    /**
     * 启动代理
     */
    private void startProxy() {
        // http访问用户名密码输入验证
        if (httpUserPane.isVisible() && StringUtils.isNotEmpty(httpUserTextField.getText())) {
            httpUserTextField.getValidators().add(TextValidate.HttpUserFormat);
            httpPwdTextField.getValidators().add(TextValidate.HttpPwdFormat);
        } else {
            httpUserTextField.getValidators().remove(TextValidate.HttpUserFormat);
            httpPwdTextField.getValidators().remove(TextValidate.HttpPwdFormat);
        }

        // 验证
        if (!domainTextField.validate() || !localHostTextField.validate() || !localPortTextField.validate() ||
                !httpUserTextField.validate() || !httpPwdTextField.validate()
        ) return;

        // 非 http 隧道系统随机分配远程端口
        if (!ProxyConfig.isHttp(proxySetupModel) && !ProxyConfig.isP2p(proxySetupModel)) {
            // 远程端口为空
            if (StringUtils.isEmpty(proxySetupModel.getRemotePort()))
                proxySetupModel.setRemotePort(String.valueOf(ProxyManager.randomPort()));
        } else {
            proxySetupModel.setRemotePort(null);
        }

        // 清空非隧道类型属性
        clearModel();

        // 是否有修改
        if (!proxySetupModel.get().equals(userProxy.get(proxySetupModel.getId()))) {
            // 添加隧道
            ProxyManager.add(new OnHttpListener<ProxySetup>() {
                @Override
                public void onSucceed(ProxySetup result) {
                    // 如果添加成功
                    if (result != null) {
                        userProxy.put(result.getId().toString(), result);
                        start(result);
                    }
                }

                @Override
                public void onFail(Exception e) {
                }
            }, proxySetupModel.get());
        } else {
            start(proxySetupModel.get());
        }
    }

    /**
     * 清空无效属性
     */
    private void clearModel() {
        boolean http = ProxyConfig.isHttp(proxySetupModel);
        boolean p2p = ProxyConfig.isP2p(proxySetupModel);
        if (http) {
            proxySetupModel.setSk(null);
            proxySetupModel.setServerName(null);
            proxySetupModel.setRemotePort("");
        } else if (p2p) {
            proxySetupModel.setHttpPwd(null);
            proxySetupModel.setHttpUser(null);
            proxySetupModel.setDomain("");
            proxySetupModel.setDomainSuffix("");
            proxySetupModel.setRemotePort("");
        } else {
            // tcp / udp
            proxySetupModel.setSk(null);
            proxySetupModel.setServerName(null);
            proxySetupModel.setHttpPwd(null);
            proxySetupModel.setHttpUser(null);
            proxySetupModel.setDomain("");
            proxySetupModel.setDomainSuffix("");
        }
    }

    private void start(ProxySetup setup) {
        // 添加成功，设置运行状态
        setup.setRuning(frpUtilMap.containsKey(setup.getId().toString()));
        proxySetupModel.set(setup);

        // 初始化frputil
        FrpManager frpManager;
        if ((frpManager = frpUtilMap.get(setup.getId().toString())) == null)
            frpUtilMap.put(proxySetupModel.getId(), frpManager = FrpManager.init(proxySetupModel));

        // 设置文本域对象
        if (proxyLogPane.getContent() == null) proxyLogPane.contentProperty().set(frpManager.getConsole());

        // 开始
        frpManager.start();

        // 显示日志
        tabPane.getSelectionModel().select(0);
    }

    /**
     * 暂停代理
     */
    private void stopProxy() {
        // 关闭CMD
        FrpManager frpManager = frpUtilMap.get(proxySetupModel.getId());
        if (frpManager != null) frpManager.stop();
    }

    @Override
    public void onDestroy() {


        super.onDestroy();
    }
}
