using Tiobon.Core.OPS.Tool.OPS.Tool.Helper;
using Tiobon.Core.OPS.Tool.OPS.Tool.Model;
using Tiobon.Core.OPS.Tool.OPS.Tool.src;
using Renci.SshNet;
using Renci.SshNet.Sftp;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Tiobon.Core.OPS.Tool.OPS.Tool.View
{
    public partial class Frm_MultiEnvironment : Form
    {
        bool isLinux = Const.config.system == "Linux";

        #region 初始化
        public Frm_MultiEnvironment()
        {
            InitializeComponent();
            this.Text = $"多环境管理 - {Const.config.name} {Const.config.ip}";
            RefreshView();
        }
        private void RefreshView(bool invoke = false)
        {
            if (invoke)
            {
                try
                {
                    BeginInvoke(new EventHandler(delegate
                    {
                        listView_MultiEnv.Items.Clear();
                        Const.MultiEnvs.Where(o => o.Ip == Const.config.ip).ForEach(o =>
                        {
                            ListViewItem item = new ListViewItem();
                            item.SubItems[0].Text = o.Name;
                            item.SubItems.Add(o.FileName);
                            item.SubItems.Add(o.DefaultPort);
                            item.SubItems.Add(o.DefaultMask);
                            listView_MultiEnv.Items.Add(item);
                        });
                    }));
                }
                catch { }
            }
            else
            {
                listView_MultiEnv.Items.Clear();
                Const.MultiEnvs.Where(o => o.Ip == Const.config.ip).ForEach(o =>
                {
                    ListViewItem item = new ListViewItem();
                    item.SubItems[0].Text = o.Name;
                    item.SubItems.Add(o.FileName);
                    item.SubItems.Add(o.DefaultPort);
                    item.SubItems.Add(o.DefaultMask);
                    listView_MultiEnv.Items.Add(item);
                });
            }
        }
        #endregion

        #region 新增、编辑、删除

        private void tsmi_Create_Click(object sender, EventArgs e)
        {
            using (Frm_MultiItem f = new Frm_MultiItem())
            {
                f.ShowDialog();
            }
            RefreshView();
        }

        private void tsmi_Edit_Click(object sender, EventArgs e)
        {
            Edit();
        }

        private void listView_MultiEnv_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            Edit();
        }

        private void Edit()
        {
            if (this.listView_MultiEnv.SelectedItems.Count <= 0)
                return;
            using (Frm_MultiItem f = new Frm_MultiItem($"{this.listView_MultiEnv.SelectedItems[0].Text}"))
            {
                f.ShowDialog();
            }
            RefreshView();
        }

        private void tsmi_Delete_Click(object sender, EventArgs e)
        {
            if (this.listView_MultiEnv.SelectedItems.Count <= 0)
                return;
            if (MessageBox.Show("是否确认删除？", "提示", MessageBoxButtons.YesNo) != DialogResult.Yes)
            {
                return;
            }
            var item = Const.MultiEnvs.Where(o => o.Ip == Const.config.ip && o.Name == this.listView_MultiEnv.SelectedItems[0].Text).FirstOrDefault();
            if (!(item is null))
            {
                Const.MultiEnvs.Remove(item);
                Const.SaveMultiEnv();
                RefreshView();
            }
        }
        #endregion

        #region 重启

        private void tsmi_Restart_Click(object sender, EventArgs e)
        {
            if (this.listView_MultiEnv.SelectedItems.Count <= 0)
                return;
            if (this.listView_MultiEnv.SelectedItems.Count <= 0)
                return;
            var name = this.listView_MultiEnv.SelectedItems[0].Text;
            if (MessageBox.Show($"是否确认重启[{name}]？", "提示", MessageBoxButtons.YesNo) != DialogResult.Yes)
            {
                return;
            }
            var item = Const.MultiEnvs.Where(o => o.Ip == Const.config.ip && o.Name == name).FirstOrDefault();
            var exist = Exists($"/home/{Const.config.ssh_user}/ihdis/{item.FileName}");
            if (!exist)
            {
                MessageBox.Show($"环境[{name}]未部署，不执行此操作", "提示");
                return;
            }
            try
            {
                LoadingHelper.ShowLoading("正在重启服务，请稍等...", this, (obj) =>
                {
                    var b_suc = ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart;", out string result);
                    Thread.Sleep(2000);
                    ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart rtm", out _);
                    Thread.Sleep(5000);
                    ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart job", out _);
                    Thread.Sleep(2000);
                    ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart hfs", out _);
                    Thread.Sleep(2000);
                    ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart iot", out _);
                    Thread.Sleep(2000);
                    ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart ts", out _);
                    Thread.Sleep(2000);
                    ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart webapi", out _);
                    Thread.Sleep(10000);
                    ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart nginx", out _);

                    if (b_suc)
                    {
                        MessageBox.Show($"环境[{name}]重启成功!", "提示");
                    }
                    else
                    {
                        MessageBox.Show($"环境[{name}]重启失败:\r\n{result}", "提示");
                    }
                });
            }
            catch { }
        }
        #endregion

        #region 停止
        private void tsmi_Stop_Click(object sender, EventArgs e)
        {
            if (this.listView_MultiEnv.SelectedItems.Count <= 0)
                return;
            var name = this.listView_MultiEnv.SelectedItems[0].Text;
            if (MessageBox.Show($"是否确认停止[{name}]？", "提示", MessageBoxButtons.YesNo) != DialogResult.Yes)
            {
                return;
            }
            var item = Const.MultiEnvs.Where(o => o.Ip == Const.config.ip && o.Name == name).FirstOrDefault();
            var exist = Exists($"/home/{Const.config.ssh_user}/ihdis/{item.FileName}");
            if (!exist)
            {
                MessageBox.Show($"环境[{name}]未部署，不执行此操作", "提示");
                return;
            }
            try
            {
                LoadingHelper.ShowLoading("正在停止服务，请稍等...", this, (obj) =>
                {
                    var b_suc = ExecSsh($"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose stop;", out string result);
                    if (b_suc)
                    {
                        MessageBox.Show($"环境[{name}]停止成功!", "提示");
                    }
                    else
                    {
                        MessageBox.Show($"环境[{name}]停止失败:\r\n{result}", "提示");
                    }
                });
            }
            catch { }
        }
        #endregion

        #region 前端
        private void tsmi_Web_Click(object sender, EventArgs e)
        {
            if (this.listView_MultiEnv.SelectedItems.Count <= 0)
                return;
            try
            {
                var item = Const.MultiEnvs.Where(o => o.Ip == Const.config.ip && o.Name == this.listView_MultiEnv.SelectedItems[0].Text).FirstOrDefault();
                var exist = Exists($"/home/{Const.config.ssh_user}/ihdis/{item.FileName}");
                if (!exist)
                {
                    MessageBox.Show($"环境[{item.Name}]未部署，不执行此操作", "提示");
                    return;
                }
                System.Diagnostics.Process.Start($"http://{item.Ip}:{item.DefaultPort}00");
            }
            catch { }
        }
        #endregion

        #region 数据库
        private void tsmi_Database_Click(object sender, EventArgs e)
        {
            if (this.listView_MultiEnv.SelectedItems.Count <= 0)
                return;
            try
            {
                var item = Const.MultiEnvs.Where(o => o.Ip == Const.config.ip && o.Name == this.listView_MultiEnv.SelectedItems[0].Text).FirstOrDefault();
                var exist = Exists($"/home/{Const.config.ssh_user}/ihdis/{item.FileName}");
                if (!exist)
                {
                    MessageBox.Show($"环境[{item.Name}]未部署，不执行此操作", "提示");
                    return;
                }
                string heidisql = @"C:\Program Files\HeidiSQL\heidisql.exe";

                if (!File.Exists(heidisql))
                {
                    MessageBox.Show($"未能检测到 [HeidiSQL]，请先安装！\r\n默认检测路径为：{heidisql}", "提示");
                }
                else
                {
                    System.Diagnostics.Process.Start(heidisql, $" -d {item.Ip}({item.FileName}) -n {0} -h {item.Ip} -u root -p jlmed#123 -P {item.DefaultPort}90");
                }
            }
            catch { }
        }
        #endregion

        #region 数据库初始化
        private void tsmi_DBInit_Click(object sender, EventArgs e)
        {
            if (this.listView_MultiEnv.SelectedItems.Count <= 0)
                return;
            var name = this.listView_MultiEnv.SelectedItems[0].Text;
            if (MessageBox.Show($"此操作存在极高风险\r\n1、会重置数据密码为jlmed#123\r\n2、现有数据将丢失，数据库重置为初始状态\r\n是否确认初始化数据库[{name}]？", "提示", MessageBoxButtons.YesNo) != DialogResult.Yes)
            {
                return;
            }
            var item = Const.MultiEnvs.Where(o => o.Ip == Const.config.ip && o.Name == name).FirstOrDefault();
            var exist = Exists($"/home/{Const.config.ssh_user}/ihdis/{item.FileName}");
            if (!exist)
            {
                MessageBox.Show($"环境[{name}]未部署，不执行此操作", "提示");
                return;
            }
            if (MessageBox.Show($"是否已经联系过研发，确认必须执行此操作？", "提示", MessageBoxButtons.YesNo) != DialogResult.Yes)
            {
                return;
            }
            try
            {
                LoadingHelper.ShowLoading("正在初始化数据库，请稍等...", this, (obj) =>
                {
                    var script = $"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose exec -T mysql mysql -uroot -hlocalhost mysql --default-character-set=utf8 < conf/mysql/hdis_db.sql;";
                    Const.write_log($"初始化数据库:{script}");
                    var b_suc = ExecSsh(script, out string result);
                    if (!b_suc)
                    {
                        Const.write_log($"初始化数据库:{result}");
                        MessageBox.Show($"初始化数据库:{result}", "提示");
                        return;
                    }
                    Const.write_log($"初始化数据库成功");
                    System.Threading.Thread.Sleep(10000);

                    script = $"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose exec -T mysql mysql -uroot -hlocalhost hdis --default-character-set=utf8 < conf/mysql/hdis_table.sql;";
                    Const.write_log($"初始化数据库表:{script}");
                    b_suc = ExecSsh(script, out result);
                    if (!b_suc)
                    {
                        Const.write_log($"初始化数据库表失败:{result}");
                        MessageBox.Show($"初始化数据库表失败:\r\n{result}", "提示");
                        return;
                    }
                    Const.write_log($"初始化数据库表成功");
                    System.Threading.Thread.Sleep(10000);

                    script = $"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose exec -T mysql mysql -uroot -hlocalhost mysql --default-character-set=utf8 < conf/mysql/hdis_user.sql;";
                    Const.write_log($"初始化用户信息:{script}");
                    b_suc = ExecSsh(script, out result);
                    if (!b_suc)
                    {
                        Const.write_log($"初始化用户信息失败:{result}");
                        MessageBox.Show($"初始化用户信息失败:\r\n{result}", "提示");
                        return;
                    }
                    Const.write_log($"初始化用户信息成功");
                    System.Threading.Thread.Sleep(10000);

                    script = $"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose exec -T mysql mysql -uroot -hlocalhost -e \"ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'jlmed#123'; flush privileges; \";";
                    Const.write_log($"初始化用户密码:{script}");
                    b_suc = ExecSsh(script, out result);
                    if (!b_suc)
                    {
                        Const.write_log($"初始化用户密码失败:{result}");
                        MessageBox.Show($"初始化用户密码失败:\r\n{result}", "提示");
                        return;
                    }
                    Const.write_log($"初始化用户密码成功");
                    System.Threading.Thread.Sleep(10000);

                    script = $"cd /home/{Const.config.ssh_user}/ihdis/{item.FileName};sudo docker-compose restart;";
                    Const.write_log($"重启服务:{script}");
                    b_suc = ExecSsh(script, out result);
                    if (!b_suc)
                    {
                        Const.write_log($"重启服务失败:{result}");
                        MessageBox.Show($"重启服务失败:\r\n{result}", "提示");
                        return;
                    }
                    Const.write_log($"重启服务成功");
                });
            }
            catch { }
        }
        #endregion

        #region 同步
        private void ll_Sync_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            try
            {
                LoadingHelper.ShowLoading("正在同步数据，请稍等...", this, (obj) =>
                {
                    if (isLinux)
                    {
                        var hospitals = ListDirectory($"/home/{Const.config.ssh_user}/ihdis").Select(o => o.Name).ToList();
                        hospitals.ForEach(hospitalName =>
                        {
                            //服务器端数据
                            if (!Exists($"/home/{Const.config.ssh_user}/ihdis/{hospitalName}/.env"))
                            {
                                Const.write_log($"发现 文件夹 {hospitalName} 不存在 .env 文件，跳过同步");
                                return;
                            }

                            var fname = GetTempFileName(".env");
                            bool b_suc = DownloadFile($"/home/{Const.config.ssh_user}/ihdis/{hospitalName}/.env", fname);
                            var content = File.ReadAllText(fname);
                            var datas = content.Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries).ToList();
                            var hospital = new MultiEnvInfo
                            {
                                Name = hospitalName,
                                FileName = hospitalName,
                                Ip = Const.config.ip,
                                DefaultPort = datas.Where(d => d.StartsWith("IHDIS_PORT=")).FirstOrDefault()?.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries)[1].Trim(),
                                DefaultMask = datas.Where(d => d.StartsWith("mask=")).FirstOrDefault()?.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries)[1].Trim(),
                            };

                            //是否存在
                            var item = Const.MultiEnvs.Where(o => o.Ip == Const.config.ip && o.FileName == hospitalName).FirstOrDefault();
                            if (item == null)
                            {
                                if (b_suc)
                                {
                                    Const.MultiEnvs.Add(hospital);
                                    Const.write_log($"发现新环境 {hospitalName} 端口 {hospital.DefaultPort} 掩码 {hospital.DefaultMask}");
                                }
                            }
                            else
                            {
                                if (item.DefaultPort != hospital.DefaultPort || item.DefaultMask != hospital.DefaultMask)
                                {
                                    Const.write_log($"更新环境 {hospitalName} 端口号 {item.DefaultPort} 掩码 {hospital.DefaultMask}");
                                    item.DefaultPort = hospital.DefaultPort;
                                }
                                else
                                {
                                    Const.write_log($"医院 {hospitalName} 端口号一致 {hospital.DefaultPort} 掩码一致 {DefaultMask}");
                                }
                            }
                        });

                        //本地数据
                        var notExsit = new List<MultiEnvInfo>();
                        Const.MultiEnvs.Where(o => o.Ip == Const.config.ip).ForEach(hospital =>
                        {
                            if (!hospitals.Contains(hospital.FileName))
                            {
                                notExsit.Add(hospital);
                            }
                        });
                        notExsit.ForEach(hospital =>
                        {
                            Const.MultiEnvs.Remove(hospital);
                            //环境不存在
                            Const.write_log($"环境已经不存在 {hospital.FileName}");
                        });
                        Const.SaveMultiEnv();
                        RefreshView(true);
                    }
                    else
                    {
                        var hospitals = new List<string>();
                        DirectoryInfo directory = new DirectoryInfo(Const.config.install_dir);
                        FileSystemInfo[] filesArray = directory.GetFileSystemInfos();
                        //foreach (var filesItem in filesArray)
                        filesArray.ForEach(filesItem =>
                        {
                            //是否是一个文件夹
                            if (filesItem.Attributes == FileAttributes.Directory)
                            {
                                var hospitalName = filesItem.Name;
                                //服务器端数据
                                if (!File.Exists($"{filesItem.FullName}/.env"))
                                {
                                    Const.write_log($"发现 文件夹 {hospitalName} 不存在 .env 文件，跳过同步");
                                    return;
                                }
                                hospitals.Add(hospitalName);
                                var content = File.ReadAllText($"{filesItem.FullName}/.env");
                                var datas = content.Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries).ToList();
                                var hospital = new MultiEnvInfo
                                {
                                    Name = hospitalName,
                                    FileName = hospitalName,
                                    Ip = Const.config.ip,
                                    DefaultPort = datas.Where(d => d.StartsWith("IHDIS_PORT=")).FirstOrDefault()?.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries)[1].Trim(),
                                    DefaultMask = datas.Where(d => d.StartsWith("mask=")).FirstOrDefault()?.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries)[1].Trim(),
                                };

                                //是否存在
                                var item = Const.MultiEnvs.Where(o => o.Ip == Const.config.ip && o.FileName == hospitalName).FirstOrDefault();
                                if (item == null)
                                {
                                    Const.MultiEnvs.Add(hospital);
                                    Const.write_log($"发现新环境 {hospitalName} 端口 {hospital.DefaultPort} 掩码 {hospital.DefaultMask}");
                                }
                                else
                                {
                                    if (item.DefaultPort != hospital.DefaultPort || item.DefaultMask != hospital.DefaultMask)
                                    {
                                        Const.write_log($"更新环境 {hospitalName} 端口号 {item.DefaultPort} 掩码 {hospital.DefaultMask}");
                                        item.DefaultPort = hospital.DefaultPort;
                                    }
                                    else
                                    {
                                        Const.write_log($"医院 {hospitalName} 端口号一致 {hospital.DefaultPort} 掩码一致 {DefaultMask}");
                                    }
                                }
                            }

                        });

                        //本地数据
                        var notExsit = new List<MultiEnvInfo>();
                        Const.MultiEnvs.Where(o => o.Ip == Const.config.ip).ForEach(hospital =>
                        {
                            if (!hospitals.Contains(hospital.FileName))
                                notExsit.Add(hospital);
                        });
                        notExsit.ForEach(hospital =>
                        {
                            Const.MultiEnvs.Remove(hospital);
                            //环境不存在
                            Const.write_log($"环境已经不存在 {hospital.FileName}");
                        });
                        Const.SaveMultiEnv();
                        RefreshView(true);
                    }
                });
            }
            catch { }
        }
        #endregion

        #region 辅助方法
        private bool ExecSsh(string command, out string result)
        {
            bool b_suc = false;
            result = string.Empty;
            try
            {
                using (SshClient ssh = new SshClient(Const.config.ip, Convert.ToInt32(Const.config.ssh_port), "root", Const.config.supasswd))
                {
                    ssh.Connect();

                    var cmd = ssh.RunCommand(command);
                    if (cmd.ExitStatus != 0)
                    {
                        result = cmd.Error;
                    }
                    else
                    {
                        b_suc = true;
                        result = $"{cmd.Result}{cmd.Error}";
                    }
                }
            }
            catch (Exception ex)
            {
                result = ex.Message;
            }
            Const.write_log(result);
            return b_suc;
        }

        private bool Exists(string path)
        {
            bool b_suc = false;
            try
            {
                using (SftpClient sftp = new SftpClient(Const.config.ip, Convert.ToInt32(Const.config.ssh_port), "root", Const.config.supasswd))
                {
                    sftp.Connect();
                    b_suc = sftp.Exists(path);
                }
            }
            catch (Exception ex)
            {
                Const.write_log(ex.ToString());
            }
            return b_suc;
        }
        /// <summary>
        /// 获取当前目录的文件夹列表
        /// </summary>
        /// <param name="server"></param>
        /// <param name="remotePath"></param>
        /// <returns></returns>
        private List<SftpFile> ListDirectory(string remotePath)
        {
            List<SftpFile> list = new List<SftpFile>();
            try
            {
                using (SftpClient sftp = new SftpClient(Const.config.ip, Convert.ToInt32(Const.config.ssh_port), "root", Const.config.supasswd))
                {
                    sftp.Connect();
                    list = sftp.ListDirectory(remotePath).Where(f => f.IsDirectory && f.Name != "." && f.Name != "..").ToList();
                }
            }
            catch (Exception ex)
            {
                Const.write_log($"获取文件夹失败：{remotePath} {ex.Message}");
            }
            return list;
        }
        /// <summary>
        /// 下载单个文件
        /// </summary>
        /// <param name="remotePath"></param>
        /// <param name="localFile"></param>
        /// <returns></returns>
        public static bool DownloadFile(string remoteFile, string localFile)
        {
            bool b_suc = false;
            try
            {
                using (SftpClient sftp = new SftpClient(Const.config.ip, Convert.ToInt32(Const.config.ssh_port), "root", Const.config.supasswd))
                {
                    sftp.Connect();
                    if (sftp.Exists(remoteFile))
                    {
                        Const.write_log($"下载文件 {remoteFile}");
                        if (File.Exists(localFile))
                        {
                            File.Delete(localFile);
                            System.Threading.Thread.Sleep(50);
                        }
                        var sftFile = sftp.ListDirectory(remoteFile.Substring(0, remoteFile.LastIndexOf('/'))).Where(o => o.FullName == remoteFile).FirstOrDefault();
                        using (var file = File.OpenWrite(localFile))
                        {
                            sftp.DownloadFile(remoteFile, file);
                            Const.write_log($"成功 {remoteFile}  =>> {localFile} len {file.Length} byte");
                            b_suc = true;
                        }
                    }
                    else
                    {
                        Const.write_log($"文件不存在 {remoteFile}");
                    }
                }
            }
            catch (Exception ex)
            {
                Const.write_log($"下载文件失败：{remoteFile} {ex.Message}");
            }
            return b_suc;
        }
        /// <summary>
        /// 获取临时文件名
        /// </summary>
        /// <param name="fname"></param>
        /// <param name="random"></param>
        /// <returns></returns>
        private string GetTempFileName(string fname, bool random = true)
        {
            return $"{System.Environment.GetEnvironmentVariable("TEMP")}\\{fname}" + (random ? $"_{DateTime.Now.Ticks}" : "");
        }
        #endregion
    }
}
