using Microsoft.VisualBasic;
using Newtonsoft.Json.Linq;
using PTMedicalInsurance;
using PTMedicalInsurance.Common;
using PTMedicalInsurance.Entity;
using PTMedicalInsurance.Entity.Local;
using PTMedicalInsurance.Helper;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PTMedicalInsurance.Forms
{
    public partial class JsonMappingForm : Form
    {

        List<FieldMapping> fieldMappings = new List<FieldMapping>();

        private bool baseToLocal = true;

        private bool orginInputFlag = true;

        string separator = ">";

        string arrayPattern = "[]";

        JsonMapper mapper;

        public JsonMappingForm()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="baseJson">基线实例</param>
        /// <param name="localJson">本地实例</param>
        /// <param name="tradeName">交易名称</param>
        public JsonMappingForm(string baseJson, string localJson, string tradeName, bool inputFlag = true)
        {
            InitializeComponent();
            txtBase.Text = baseJson;
            txtLocal.Text = localJson;
            txtName.Text = tradeName;
            this.baseToLocal = inputFlag;
            this.orginInputFlag = inputFlag;  //原始状态
            // 初始化mapper
            mapper = new JsonMapper(txtName.Text);
            txtName.Enabled = false;
        }

        private void JsonMappingForm_Load(object sender, EventArgs e)
        {
            btnMap.Enabled = false;
            if (!this.baseToLocal)
            {
                radioOutput.Checked = true;
            }

            this.loadFieldMapping();
            this.loadConfig();

        }

        private void btnLoad_Click(object sender, EventArgs e)
        {
            loadFieldMapping();
        }

        private void loadFieldMapping()
        {
            lstBase.Items.Clear();
            lstLocal.Items.Clear();

            btnMap.Enabled = true;
            //btnLoad.Enabled = false;

            if (!string.IsNullOrEmpty(txtBase.Text.Trim()))
            {
                JObject joInput = JObject.Parse(txtBase.Text);
                parseJsonToList(joInput, this.lstBase, new StringBuilder());
            }

            if (!string.IsNullOrEmpty(txtLocal.Text.Trim()))
            {
                JObject joInput = JObject.Parse(txtLocal.Text);
                parseJsonToList(joInput, this.lstLocal, new StringBuilder());
            }
        }

        private void parseJsonToList(JToken jToken, ListBox lstBox, StringBuilder sb)
        {
            if (jToken is JProperty jProperty)
            {
                if (sb.Length > 0)
                {
                    sb.Append(".");
                }
                sb.Append(jProperty.Name);
                parseJsonToList(jProperty.Value, lstBox, sb);
            }
            else if (jToken is JArray jArray)
            {
                sb.Append("[]");
                if (jArray.Count > 0)
                {
                    var item = jArray[0]; // only load first row
                    parseJsonToList(item, lstBox, new StringBuilder(sb.ToString()));
                }
            }
            else if (jToken is JObject jObject)
            {
                foreach (var property in jObject.Properties())
                {
                    parseJsonToList(property, lstBox, new StringBuilder(sb.ToString()));
                }
            }
            else
            {
                // 输出最终结果
                lstBox.Items.Add(sb.ToString());
            }
            // JValue
        }

        private void btnMap_Click(object sender, EventArgs e)
        {
            baseToLocal = radioInput.Checked;

            if (lstBase.SelectedIndex < 0)
            {
                MessageBox.Show("请先选中基线版属性!");
                return;
            }

            if (lstLocal.SelectedIndex < 0)
            {
                MessageBox.Show("请先选中地方版属性!");
                return;
            }
            AddMapping();
        }

        private void AddMapping()
        {
            FieldMapping field = new FieldMapping();
            string sKey = lstBase.SelectedItem.ToString();
            string tKey = lstLocal.SelectedItem.ToString();
            field.Source = sKey;
            field.Target = tKey;

            string text = field.Source + separator + field.Target;
            if (!this.baseToLocal)
            {
                text = field.Target + separator + field.Source;
                field.Source = lstLocal.SelectedItem.ToString();
                field.Target = lstBase.SelectedItem.ToString();
            }
            if ("saveToExpand".Equals(field.Expression))
            {
                text += "(*)";
            }
            FieldMapping orginField = null;
            // array
            List <FieldMapping> childs = null;
            if (field.Source.Contains(arrayPattern) && field.Target.Contains(arrayPattern))
            {
                sKey = field.Source.Split(arrayPattern.ToCharArray())[0] + arrayPattern;
                tKey = field.Target.Split(arrayPattern.ToCharArray())[0] + arrayPattern;
                orginField = fieldMappings.FirstOrDefault(m => m.Source == sKey && m.Target == tKey)??new FieldMapping();
                childs = orginField.Child??new List<FieldMapping>();
                orginField.Source = sKey;
                orginField.Target = tKey;
                field.Source = field.Source.Replace(sKey + ".", "");
                field.Target = field.Target.Replace(tKey + ".", "");
            }
            if (childs != null)
            {
                if (!childs.Contains(field))
                {
                    childs.Add(field);
                    orginField.Child = childs;
                    if(!fieldMappings.Contains(orginField))
                    {
                            fieldMappings.Add(orginField);
                    }
                }
            }
            else
            {
                fieldMappings.Add(field);
            }


            lstMap.Items.Add(text);
            // clear selectedItem
            lstLocal.Items.Remove(lstLocal.SelectedItem);
            lstBase.Items.Remove(lstBase.SelectedItem);

        }

        private void lstMap_DoubleClick(object sender, EventArgs e)
        {
            string text = lstMap.SelectedItem.ToString();
            string[] fields = text.Split(separator.ToCharArray());
            if (!fields[1].Contains("【"))
            {
                if (this.baseToLocal)
                {
                    if (!lstBase.Items.Contains(fields[0])) lstBase.Items.Add(fields[0]);
                    if (!lstLocal.Items.Contains(fields[1])) lstLocal.Items.Add(fields[1]);
                }
                else
                {
                    if (!lstBase.Items.Contains(fields[1])) lstBase.Items.Add(fields[1]);
                    if (!lstLocal.Items.Contains(fields[0])) lstLocal.Items.Add(fields[0]);
                }
            }
            fields[1] = fields[1].Replace("【】", "");
            FieldMapping field = QuerySelectedField();
            if (field != null)
            {
                this.fieldMappings.Remove(field);
            }
            lstMap.Items.Remove(lstMap.SelectedItem);
            
        }

        private FieldMapping QuerySelectedField()
        {
            if (lstMap.SelectedItem == null) return null;
            // TODO:如果目标是数组未处理  
            string text = lstMap.SelectedItem.ToString();
            string[] fields = text.Split(separator.ToCharArray());
            // remove from fieldMapping
            string txtValue = fields[1].Replace("【","").Replace("】","");
            FieldMapping field = this.fieldMappings.FirstOrDefault(m => (m.Source == fields[0] && m.Target == fields[1]) || (m.Target == fields[0] && m.Value == txtValue));
            return field;
        }

        private void btnConfig_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(txtName.Text))
            {
                MessageBox.Show("请输入交易名称!");
                return;
            }

            if (lstMap.Items.Count > 0) {
                if (!Utils.Confirm("加载配置将清除已有配置，您确定要加载吗？"))
                {
                    return;
                }
                lstMap.Items.Clear();
            }
            loadConfig();
        }
        
        private void loadConfig()
        {
            this.baseToLocal = radioInput.Checked;
            if(this.mapper == null)
            {
                mapper = new JsonMapper(txtName.Text);
            }
            mapper.reload();

            if (this.baseToLocal)
            {
                fieldMappings = mapper.GetInputMapping();
                loadConfigMapping();
            }
            else
            {
                fieldMappings = mapper.GetOutputMapping();
                loadConfigMapping();
            }

            
        }

        private void loadConfigMapping(bool clearFlag = true)
        {
            lstMap.Items.Clear();
            if (fieldMappings?.Count > 0)
            {
                fieldMappings.ForEach((map) =>
                {
                    if (map.Child != null)
                    {
                        map.Child.ForEach((m) => loadChildMapping(m, clearFlag, map.Source+".",map.Target + "."));
                    }
                    else
                    {
                        loadChildMapping(map);
                    }
                    
                });
            }
        }

        private void loadChildMapping(FieldMapping map,bool clearFlag = true, string srcRoot = "",string destRoot = "")
        {
            string text = srcRoot + map.Source + separator + destRoot + map.Target;
            if ("saveToExpand".Equals(map.Expression))
            {
                text += "(*)";
            }
            if (string.IsNullOrEmpty(map.Source))
            {
                text = destRoot + map.Target + separator + "【" +  map.Value + "】";
            }
            else
            {
                if (clearFlag)
                {
                    // clear selectedItem
                    lstBase.Items.Remove(srcRoot+map.Source);
                    lstLocal.Items.Remove(destRoot+map.Target);
                }
            }

            lstMap.Items.Add(text);
        }

        private void btnTest_Click(object sender, EventArgs e)
        {
            if (mapper == null) return;

            try
            {
                JObject joRtn = new JObject();
                if (this.baseToLocal)
                {
                    // 转换入参
                    if (this.fieldMappings != null)
                    {
                        mapper.SetInputMapping(this.fieldMappings);
                        joRtn = mapper.MapRequest<JObject, JObject>(JObject.Parse(txtBase.Text));
                    }
                }
                else
                {
                    // 出参
                    if (this.fieldMappings != null)
                    {
                        mapper.SetOutputMapping(this.fieldMappings);
                        joRtn = mapper.MapResponse<JObject, JObject>(JObject.Parse(txtBase.Text));
                    }
                }

                this.txtLocal.Clear();
                this.txtLocal.AppendText(JsonHelper.toJsonString(joRtn));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            if (!Utils.Confirm("将覆盖原有数据，您确定要保存吗？"))
            {
                return;
            }
            if (this.baseToLocal)
            {
                //入参
                mapper.SetInputMapping(this.fieldMappings);
            }
            else
            {
                mapper.SetOutputMapping(this.fieldMappings);
            }
            mapper.Save();
            MessageBox.Show("保存成功!");
        }

        private void radioInput_CheckedChanged(object sender, EventArgs e)
        {
            this.baseToLocal = radioInput.Checked;
        }

        private void btnChange_Click(object sender, EventArgs e)
        {
            mapper.ChangeDirection(this.fieldMappings);
            if(orginInputFlag)
            {
                this.loadConfigMapping(false);
            }
            else
            {
                this.loadConfigMapping(false);
            }
            

        }

        private void btnMockLocal_Click(object sender, EventArgs e)
        {
            txtLocal.Clear();
            txtLocal.AppendText(Utils.MockData(radioInput.Checked, txtName.Text));
        }

        private void txtLocalName_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                int index = lstLocal.FindString(txtLocalName.Text.Trim());
                lstLocal.SelectedIndex = index;
            }
        }

        private void btnExchange_Click(object sender, EventArgs e)
        {
            string text = txtBase.Text;
            txtBase.Text = txtLocal.Text;
            txtLocal.Text = text;
        }

        private void txtBaseName_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                int index = lstBase.FindString(txtBaseName.Text.Trim());
                lstBase.SelectedIndex = index;
            }
        }

        private void fixValue_Click(object sender, EventArgs e)
        {
            string strValue = Interaction.InputBox("请输入");
            string text = lstLocal.SelectedItem + separator + "【" + strValue + "】";
            lstMap.Items.Add(text);

            string target = lstLocal.SelectedItem.ToString();

            if (target.Contains(arrayPattern))
            {
                string prefix_target = target.Substring(0, target.IndexOf(arrayPattern) + 2);
                var rtn = GetFieldMappingByTarget(prefix_target);
                FieldMapping fieldMapping = rtn.mapping;
                if (!rtn.exists)
                {
                    this.fieldMappings.Add(rtn.mapping);
                }
                
                fieldMapping.Target = prefix_target;
                List<FieldMapping> childs = fieldMapping.Child ?? new List<FieldMapping>();
                string subKey = target.Replace(prefix_target + ".", "");

                FieldMapping subField = childs.FirstOrDefault(m => (m.Target == subKey));
                if (subField == null)
                {
                    subField = new FieldMapping();
                    childs.Add(subField);
                }
                subField.Source = null;
                subField.Target = subKey;
                subField.Value = strValue;
            }
            else
            {
                var rtn = GetFieldMappingByTarget(target);
                FieldMapping fieldMapping = rtn.mapping;
                if (!rtn.exists)
                {
                    this.fieldMappings.Add(rtn.mapping);
                }
                fieldMapping.Target = target;
                fieldMapping.Value = strValue;
            }

            // clear selectedItem
            lstLocal.Items.Remove(lstLocal.SelectedItem);
        }


        private (bool exists,FieldMapping mapping) GetFieldMappingByTarget(string target)
        {
            FieldMapping fieldMapping = this.fieldMappings.FirstOrDefault(m => (m.Target == target));
            //数组中的固定值
            if (fieldMapping == null)
            {
                fieldMapping = new FieldMapping();
                return (false, fieldMapping);
            }
            return (true,fieldMapping);
        }

        private void AddGlobalVar(string key)
        {
            FieldMapping fieldMapping = new FieldMapping();
            fieldMapping.Target = lstLocal.SelectedItem.ToString();
            fieldMapping.Source = "Global_"+key;
            fieldMapping.Expression = "GlobaVariables";
            this.fieldMappings.Add(fieldMapping);

            string text = fieldMapping.Source + separator + fieldMapping.Target;
            lstMap.Items.Add(text);
            // clear selectedItem
            lstLocal.Items.Remove(lstLocal.SelectedItem);
        }

        private void medtrt_id_Click(object sender, EventArgs e)
        {
            AddGlobalVar("mdtrtid");
        }

        private void insuplc_admvs_Click(object sender, EventArgs e)
        {
            AddGlobalVar("insuplc");
        }

        private void insuadm_admvs_Click(object sender, EventArgs e)
        {
            AddGlobalVar("mdtrtarea");
        }

        private void pns_no_Click(object sender, EventArgs e)
        {
            AddGlobalVar("psn");
        }

        private void psn_name_Click(object sender, EventArgs e)
        {
            AddGlobalVar("name");
        }

        private void gender_Click(object sender, EventArgs e)
        {
            AddGlobalVar("gender");
        }

        private void age_Click(object sender, EventArgs e)
        {
            AddGlobalVar("age");
        }

        private void btnBaseMock_Click(object sender, EventArgs e)
        {
            txtLocal.Clear();
            txtLocal.AppendText(Utils.MockData(radioInput.Checked, txtName.Text));
        }

        private void medtype_Click(object sender, EventArgs e)
        {
            AddGlobalVar("medtype");
        }

        private void insutype_Click(object sender, EventArgs e)
        {
            AddGlobalVar("insutype");
        }

        private void birthday_Click(object sender, EventArgs e)
        {
            AddGlobalVar("birthday");
        }

        private void stringToDate_Click(object sender, EventArgs e)
        {
            FieldMapping mapping = QuerySelectedField();
            if (mapping != null)
            {
                mapping.Expression = "ShortDate";
            }
        }

        private void numToDate_Click(object sender, EventArgs e)
        {
            FieldMapping mapping = QuerySelectedField();
            if (mapping != null)
            {
                mapping.Expression = "LongToDate";
            }
        }

        private void ecToken_Click(object sender, EventArgs e)
        {
            AddGlobalVar("ectoken");
        }

        private void saveToExpand_Click(object sender, EventArgs e)
        {
            FieldMapping fieldMapping = new FieldMapping();
            fieldMapping.Source = lstLocal.SelectedItem.ToString();
            fieldMapping.Expression = "SaveToExpand";
            this.fieldMappings.Add(fieldMapping);

            string text = fieldMapping.Source + separator + "(*)";
            lstMap.Items.Add(text);

            // clear selectedItem
            lstLocal.Items.Remove(lstLocal.SelectedItem);
        }

        private void clearway_Click(object sender, EventArgs e)
        {
            AddGlobalVar("clearway");
        }

        private void ToString_Click(object sender, EventArgs e)
        {
            FieldMapping mapping = QuerySelectedField();
            if (mapping != null)
            {
                mapping.Expression = "ConvertToString";
            }
        }

        private void insuOrgCode_Click(object sender, EventArgs e)
        {
            AddGlobalVar("insuorg");
        }

        private void admid_Click(object sender, EventArgs e)
        {
            AddGlobalVar("admid");
        }

        private void certtype_Click(object sender, EventArgs e)
        {
            AddGlobalVar("certtype");
        }

        private void certno_Click(object sender, EventArgs e)
        {
            AddGlobalVar("certno");
        }
    }
}
