using DDUtilityApp.LOGPARSER.DATA;
using JWH;
using JWH.NETWORK;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using Telerik.WinControls.UI;

namespace DDUtilityApp.MESDOWNLOADER
{
    public partial class FrmServerLog: Form
    {

        private DataSet DSSetting { get; set; } = null;

        private DataTable DTFileInfo { get; set; } = null;

        public FrmServerLog()
        {
            InitializeComponent();

            this.SetLayout();
            this.SetEventHandler();
        }

        private void SetLayout()
        {
            try
            {
#if DEBUG
                this.Text = $"ServerLog Download - Ver. {Application.ProductVersion} : DEBUG";
#else
                this.Text = $"ServerLog Download - Ver. {Application.ProductVersion}";
#endif
                this.Font = new Font("돋움체", 9);

                this.CreateDTFileInfo();
                this.SetCboxServer();
                this.GridFiles_Setting();

                this.tboxDownPath.ReadOnly = true;
                this.tboxDownPath.Text = GlobalVariable.Instance.DownloadPathServerLog;
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex, true);
            }
        }

        private void SetEventHandler()
        {
            try
            {
                this.cboxServer.SelectedIndexChanged += this.CboxServer_SelectedIndexChanged;
                this.btnRefresh.Click += this.BtnRefresh_Click;
                this.btnDownPathChange.Click += this.BtnDownPathChange_Click;
                this.btnDownPathOpen.Click += this.BtnDownPathOpen_Click;

                this.treeFolder.AfterSelect += this.TreeFolder_AfterSelect;

                this.gridFiles.CellDoubleClick += this.GridFiles_CellDoubleClick;
                this.gridFiles.KeyDown += this.GridFiles_KeyDown;
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex, true);
            }
        }

        #region [ Controls ] --------------------------------------------------

        /// <summary>
        /// 서버선택
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CboxServer_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                this.GridFiles_Setting();
                if (this.DSSetting == null || this.DSSetting.Tables.Contains("Item") == false) return;

                int value = (int)this.cboxServer.SelectedValue;
                var query = from dtServer in DSSetting.Tables["Server"].AsEnumerable()
                            join dtItem in DSSetting.Tables["Item"].AsEnumerable()
                            on dtServer.Field<int>("Server_Id") equals dtItem.Field<int>("Server_Id")
                            where dtItem.Field<int>("Server_Id") == value
                            select new
                            {
                                name = dtServer.Field<string>("name"),
                                nameap = dtItem.Field<string>("name"),
                                url = dtItem.Field<string>("url"),
                                dir = dtItem.Field<string>("dir"),
                                conkey = dtItem.Field<string>("conkey"),
                                Server_Id = dtItem.Field<int>("Server_Id"),
                            };

                foreach (Control control in this.pnlAPList.Controls)
                    control.Dispose();
                this.pnlAPList.Controls.Clear();

                int index = 0;
                foreach (var item in query)
                {
                    string[] splitIP = item.url.Split('.');
                    CheckBox chk = new CheckBox()
                    {
                        Text = $"{item.nameap} ({splitIP[splitIP.Length - 1]})",
                        AutoSize = true,
                        Checked = true,
                        Padding = new Padding(5, 3, 3, 5),
                        Margin = new Padding(0),
                        Tag = item.nameap,
                    };
                    index++;
                    this.pnlAPList.Controls.Add(chk);
                }

                this.treeFolder.Nodes.Clear();
                TreeNode rootNode = this.treeFolder.Nodes.Add("ROOT");
                this.treeFolder.SelectedNode = rootNode;
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex, true);
            }
        }

        /// <summary>
        /// 현재 (Treeview.SelectedNode)경로의 파일목록 갱신
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnRefresh_Click(object sender, EventArgs e)
        {
            try
            {
                this.Cursor = Cursors.WaitCursor;
                this.SuspendLayout();
                this.DTFileInfo.Rows.Clear();
                this.gridFiles.DataSource = null;

                int server_Id = (int)this.cboxServer.SelectedValue;
                TreeNode currentNode = this.treeFolder.SelectedNode;
                if (currentNode == null) return;
                string subPath = currentNode.Tag as string;

                foreach (Control control in this.pnlAPList.Controls)
                {
                    CheckBox chk = control as CheckBox;
                    if (chk == null || chk.Checked == false) continue;

                    string nameap = control.Tag as string;
                    if (string.IsNullOrEmpty(nameap)) continue;

                    DataRow[] rows = this.DSSetting.Tables["Item"].Select($"Server_Id='{server_Id}' AND name='{nameap}'");
                    foreach (DataRow row in rows)
                    {
                        string url = row["url"] as string;
                        string dir = row["dir"] as string;
                        string conkey = row["conkey"] as string;

                        string userId = this.GetUserIdFromConkey(conkey);
                        string password = this.GetPasswordFromConkey(conkey);
                        string currentPath = string.IsNullOrEmpty(subPath) ? dir : System.IO.Path.Combine(dir, subPath);

                        FtpsClient.Initialize(url, userId, password);
                        var files = FtpsClient.GetFtpsList(currentPath);

                        foreach (var file in files)
                        {
                            DataRow rowFile = this.DTFileInfo.NewRow();
                            rowFile["nameap"] = nameap;
                            rowFile["Name"] = file.Name;
                            rowFile["FileName"] = file.Name;
                            rowFile["Size"] = this.GetFileSize(file.Size, FileSizeType.MB);
                            rowFile["Modified"] = file.Modified.ToLocalTime();
                            rowFile["Type"] = file.Type;
                            rowFile["url"] = url;
                            rowFile["dir"] = dir;
                            rowFile["subpath"] = subPath;
                            rowFile["userId"] = userId;
                            rowFile["password"] = password;
                            this.DTFileInfo.Rows.Add(rowFile);
                        }
                    }
                }

                this.DTFileInfo.DefaultView.RowFilter = $"Type='Directory'";
                this.DTFileInfo.DefaultView.Sort = "FileName ASC";
                foreach (DataRow row in this.DTFileInfo.DefaultView.ToTable(true, "FileName").Rows)
                {

                    string fileName = row["FileName"] as string;
                    if (string.IsNullOrEmpty(fileName)) continue;
                    if (currentNode.Nodes.ContainsKey(fileName)) continue;

                    TreeNode node = currentNode.Nodes.Add(fileName, fileName);
                    node.Tag = string.IsNullOrEmpty(currentNode.Tag as string) ? fileName : System.IO.Path.Combine(currentNode.Tag as string, fileName);
                }
                currentNode.Expand();

                this.DTFileInfo.DefaultView.RowFilter = "Type='File'";
                this.DTFileInfo.DefaultView.Sort = "Modified DESC";
                this.gridFiles.DataSource = this.DTFileInfo;
                this.gridFiles.BestFitColumns();
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex, true);
            }
            finally
            {
                this.ResumeLayout();
                this.Cursor = Cursors.Default;
            }
        }

        /// <summary>
        /// 로그파일 다운로드 폴더설정
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnDownPathChange_Click(object sender, EventArgs e)
        {
            try
            {
                if (string.IsNullOrEmpty(this.tboxDownPath.Text))
                    this.tboxDownPath.Text = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

                using (FolderBrowserDialog dlg = new FolderBrowserDialog())
                {
                    dlg.SelectedPath = this.tboxDownPath.Text;
                    if (dlg.ShowDialog() == DialogResult.OK)
                    {
                        this.tboxDownPath.Text = dlg.SelectedPath;
                        GlobalVariable.Instance.DownloadPathServerLog = this.tboxDownPath.Text;
                    }
                }
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex, true);
            }
        }

        /// <summary>
        /// 로그파일 다운로드 폴더열기
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnDownPathOpen_Click(object sender, EventArgs e)
        {
            try
            {
                Process.Start("explorer.exe", this.tboxDownPath.Text);
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex, true);
            }
        }

        private void TreeFolder_AfterSelect(object sender, TreeViewEventArgs e)
        {
            this.BtnRefresh_Click(this.btnRefresh, new EventArgs());
        }

        #endregion

        #region [ GridFiles ] -------------------------------------------------

        private void GridFiles_Setting()
        {
            try
            {
                this.gridFiles.SelectionMode = GridViewSelectionMode.FullRowSelect;
                this.gridFiles.MultiSelect = true;
                this.gridFiles.TableElement.RowHeight = 22;
                this.gridFiles.Columns.Clear();
                this.gridFiles.Columns.Add(new GridViewTextBoxColumn("nameap") { HeaderText = "Server", ReadOnly = true });
                this.gridFiles.Columns.Add(new GridViewTextBoxColumn("Name") { ReadOnly=true, IsVisible = false });
                this.gridFiles.Columns.Add(new GridViewTextBoxColumn("FileName") { ReadOnly = true });
                this.gridFiles.Columns.Add(new GridViewTextBoxColumn("Size") { ReadOnly = true, TextAlignment = ContentAlignment.MiddleRight });
                this.gridFiles.Columns.Add(new GridViewDateTimeColumn("Modified") { ReadOnly = true });
                this.gridFiles.Columns.Add(new GridViewTextBoxColumn("Type") { ReadOnly = true });
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex, true);
            }
        }

        private void GridFiles_KeyDown(object sender, KeyEventArgs e)
        {
            try
            {
                if (e.KeyCode != Keys.Enter) return;

                this.GridFiles_CellDoubleClick(this.gridFiles, null);
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex, true);
            }
        }

        private async void GridFiles_CellDoubleClick(object sender, Telerik.WinControls.UI.GridViewCellEventArgs e)
        {
            try
            {
                List<DataRow> rows = new List<DataRow>();
                List<string> downloads = new List<string>();

                if (e != null)
                {
                    // 더블클릭된 파일 추가
                    DataRowView view = e.Row.DataBoundItem as DataRowView;
                    if (view != null && view.Row != null) rows.Add(view.Row);
                }
                else
                {
                    // 선택된 파일들 추가
                    List<DataRow> rowsSRC = new List<DataRow>();
                    foreach(GridViewRowInfo row in this.gridFiles.SelectedRows)
                    {
                        DataRowView view = row.DataBoundItem as DataRowView;
                        if (view != null && view.Row != null) rowsSRC.Add(view.Row);
                    }

                    // 수정일자 정렬
                    foreach (DataRow row in rowsSRC.OrderBy(row => row.Field<DateTime>("Modified")))
                        rows.Add(row);
                }

                

                // 다운로드
                bool hasZip = false;
                using (ProgressForm frmProgress = new ProgressForm(rows.Count))
                {
                    int countDown = 0;
                    frmProgress.Show();
                    frmProgress.UpdateProgress(string.Empty, countDown);

                    foreach(DataRow row in rows)
                    {
                        string fileName = row["FileName"] as string;
                        string url = row["url"] as string;
                        string dir = row["dir"] as string;
                        string subpath = row["subpath"] as string;
                        string userId = row["userId"] as string;
                        string password = row["password"] as string;

                        string extension = System.IO.Path.GetExtension(fileName);
                        if (string.Compare(extension, ".Zip", true) == 0) hasZip = true;
                        else if (string.Compare(extension, ".Log", false) == 0) fileName += ".Log";

                        List<string> paths = new List<string>();
                        if (!string.IsNullOrEmpty(dir)) paths.Add(dir);
                        if (!string.IsNullOrEmpty(subpath)) paths.Add(subpath);
                        if (!string.IsNullOrEmpty(fileName)) paths.Add(fileName);
                        string pathSRC = System.IO.Path.Combine(paths.ToArray());
                        string pathDST = System.IO.Path.Combine(this.tboxDownPath.Text, this.cboxServer.Text, fileName);
                        frmProgress.UpdateProgress($"{fileName}", countDown);

                        FtpsClient.Disconnect();
                        FtpsClient.Initialize(url, userId, password);
                        bool isSuccess = await Task.Run(() =>
                            FtpsClient.DownloadFtpsFile(pathSRC, pathDST)
                        );

                        countDown++;
                        if (isSuccess) downloads.Add(pathDST);
                    }
                }

                if (downloads.Count < 1)
                {
                    MessageBox.Show($"다운로드된 파일이 없습니다.", "", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }

                // FileMerge
                if (downloads.Count == 1)
                {
                    string fileName = downloads[0];
                    if (hasZip)
                    {
                        string path = System.IO.Path.Combine(this.tboxDownPath.Text, this.cboxServer.Text, fileName);
                        string command = $"/select,{path}";
                        Process.Start($"explorer.exe", command);
                    }
                    else
                    {
                        string extension = System.IO.Path.GetExtension(fileName);
                        if (string.Compare(extension, ".Log", true) != 0)
                            System.IO.File.Move(fileName, fileName += ".log");
                        System.Diagnostics.Process.Start(fileName);
                    }
                }
                else
                {
                    if (hasZip)
                    {
                        string path = System.IO.Path.Combine(this.tboxDownPath.Text, this.cboxServer.Text);
                        string command = $"/select,{path}";
                        Process.Start($"explorer.exe", path);
                    }
                    else
                    {
                        string fileName = Util.GetFileMerge(downloads);
                        string extension = System.IO.Path.GetExtension(fileName);
                        if (string.Compare(extension, ".Log", true) != 0)
                            System.IO.File.Move(fileName, fileName += ".log");
                        System.Diagnostics.Process.Start(fileName);
                    }
                }
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex, true);
            }
        }

        #endregion

        /// <summary>
        /// Server + File 저장테이블 생성
        /// </summary>
        /// <returns></returns>
        private void CreateDTFileInfo()
        {
            try
            {
                this.DTFileInfo = new DataTable();
                this.DTFileInfo.Columns.Add("nameap", typeof(string));
                this.DTFileInfo.Columns.Add("Name", typeof(string));
                this.DTFileInfo.Columns.Add("FileName", typeof(string));
                this.DTFileInfo.Columns.Add("Size", typeof(string));
                this.DTFileInfo.Columns.Add("Modified", typeof(DateTime));
                this.DTFileInfo.Columns.Add("Type", typeof(string));
                this.DTFileInfo.Columns.Add("url", typeof(string));
                this.DTFileInfo.Columns.Add("dir", typeof(string));
                this.DTFileInfo.Columns.Add("subpath", typeof(string));
                this.DTFileInfo.Columns.Add("userId", typeof(string));
                this.DTFileInfo.Columns.Add("password", typeof(string));
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex, true);
            }
        }

        /// <summary>
        /// XML 설정파일 로딩 및 CboxServer 셋팅
        /// </summary>
        private void SetCboxServer()
        {
            try
            {
                string path = ConfigurationManager.AppSettings["BULK_VIEWER"];
                this.DSSetting = XmlToDsConverter.ConvertXmlToDataSet(path);
                if (this.DSSetting == null || this.DSSetting.Tables.Count < 1 || this.DSSetting.Tables.Contains("Server") == false)
                {
                    MessageBox.Show("XML 데이터를 불러올 수 없습니다.", "오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                this.cboxServer.DropDownStyle = ComboBoxStyle.DropDownList;
                this.cboxServer.DataSource = DSSetting.Tables["Server"];
                this.cboxServer.DisplayMember = "name";
                this.cboxServer.ValueMember = "Server_Id";
                this.cboxServer.SelectedIndex = -1;
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex, true);
            }
        }

        /// <summary>
        /// conkey to Base64
        /// </summary>
        /// <param name="conkey"></param>
        /// <returns></returns>
        private string GetUserIdFromConkey(string conkey)
        {
            try
            {
                string value = Util.GetBase64(conkey);
                string[] items = value.Split(':');
                if (items == null || items.Length < 1) return string.Empty;

                return items[0];
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex, true);
                return string.Empty;
            }
        }

        /// <summary>
        /// conkey to Base64
        /// </summary>
        /// <param name="conkey"></param>
        /// <returns></returns>
        private string GetPasswordFromConkey(string conkey)
        {
            try
            {
                string value = Util.GetBase64(conkey);
                string[] items = value.Split(':');
                if (items == null || items.Length < 2) return string.Empty;

                return items[1];
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex, true);
                return string.Empty;
            }
        }

        public string GetFileSize(long length, FileSizeType format = FileSizeType.Auto)
        {
            int index = 0;
            int nFormat = (int)format;
            double value = length;
            for (index = 0; index < nFormat; index++)
            {
                if (format == FileSizeType.Auto && value < 1024) break;
                value /= 1024;
            }

            return $"{value.ToString("N2")} {(FileSizeType)index}";
        }

    }
}
