using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CloudBuilder.Core.Service
{
    public class SearchCriteria
    {
        public const string KEY_FILTER_COLUMN = "filter_column";
        public const string KEY_FILTER_OPERATOR = "filter_operator";
        public const string KEY_FILTER_TYPE = "filter_type";

        public SearchCriteria()
        {
            Add(KEY_FILTER_OPERATOR, SearchFilterOperatorPolicy.GetInstance().GetBindOptions());
            Add(KEY_FILTER_TYPE, SearchFilterTypePolicy.GetInstance().GetBindOptions());
        }
        public SearchCriteria(Selection[] selections)
        {
            Selections = selections;
            Add(KEY_FILTER_OPERATOR, SearchFilterOperatorPolicy.GetInstance().GetBindOptions());
            Add(KEY_FILTER_TYPE, SearchFilterTypePolicy.GetInstance().GetBindOptions());
        }
        public Selection[] Selections { get; set; }

        public void Add(string key, BindOption[] bindOptions)
        {
            if (bindOptions == null || bindOptions.Length == 0) return;
            List<Selection> selections = new List<Selection>();

            if (Selections != null)
            {
                selections.AddRange(Selections);
            }

            selections.Add(new Selection() { Key = key, BindOptions = bindOptions });

            Selections = selections.ToArray();
        }

    }

    public class Selection
    {
        public Selection() { }
        public Selection(string key, BindOption[] bindOptions)
        {
            Key = key;
            BindOptions = bindOptions;
        }

        public string Key { get; set; }
        public BindOption[] BindOptions { get; set; }
    }

    public class BindOption
    {
        public BindOption() { }
        public BindOption(string value, string name, SelectOption[] selectOptions)
        {
            BindValue = value;
            DisplayName = name;
            SelectOptions = selectOptions;
        }
        public BindOption(string value, string name, string type, string opt)
        {
            BindValue = value;
            DisplayName = name;
            Type = type;
            Operator = opt;
        }
        public BindOption(string value, string name, string type, string opt, SelectOption[] selectOptions)
        {
            BindValue = value;
            DisplayName = name;
            Type = type;
            Operator = opt;
            Values = new string[] { };
            SelectOptions = selectOptions;
        }
        public BindOption(string value, string name, string type, string opt, string defaultValue, string defaultValue1, string[] defaultValues, SelectOption[] selectOptions)
        {
            BindValue = value;
            DisplayName = name;
            Type = type;
            Operator = opt;
            Values = new string[] { };
            Value1 = defaultValue1;
            Value = defaultValue;
            Values = defaultValues;
            SelectOptions = selectOptions;
        }
        public BindOption(string value, string name, string type, string opt, string defaultValue, string defaultValue1, SelectOption[] selectOptions)
        {
            BindValue = value;
            DisplayName = name;
            Type = type;
            Operator = opt;
            Values = new string[] { };
            Value1 = defaultValue1;
            Value = defaultValue;
            SelectOptions = selectOptions;
        }
        public BindOption(string value, string name, string type, string opt, string[] defaultValues, SelectOption[] selectOptions)
        {
            BindValue = value;
            DisplayName = name;
            Type = type;
            Operator = opt;
            Values = new string[] { };
            Values = defaultValues;
            SelectOptions = selectOptions;
        }
        public string DisplayName { get; set; }
        public string BindValue { get; set; }
        public string Type { get; set; }
        public string Operator { get; set; }
        public string[] Values { get; set; }
        public string Value { get; set; }
        public string Value1 { get; set; }

        public SelectOption[] SelectOptions { get; set; }
    }

    public class SelectOption
    {
        public string DisplayName { get; set; }
        public string BindValue { get; set; }
    }

    public class SearchFilter
    {
        public SearchFilter() { }
        public SearchFilter(string column, string opt, string value)
        {
            Column = column;
            Operator = opt;
            Value = value;
        }

        public string? Column { get; set; }
        public string? Type { get; set; }
        public string? Operator { get; set; }
        public string? Value { get; set; }
        public string? Value1 { get; set; }
        public string[]? Values { get; set; }

        public static string ComposeWhereClause(SearchFilter[] searchFilters)
        {
            StringBuilder sb = new StringBuilder();

            if (searchFilters == null || searchFilters.Length == 0) return null;

            foreach (SearchFilter f in searchFilters)
            {
                if (string.IsNullOrEmpty(f.Value) && !(f.Operator == SearchFilterOperatorPolicy.DATE_BETWEEN || f.Operator == SearchFilterOperatorPolicy.BETWEEN || f.Operator == SearchFilterOperatorPolicy.DATETIME_BETWEEN)) continue;
                switch (f.Operator)
                {
                    case SearchFilterOperatorPolicy.EQUAL_TO:
                    case SearchFilterOperatorPolicy.SINGLE:
                        sb.Append(string.Format(" and {0} = '{1}' ", f.Column, QuoteString(f.Value)));
                        break;
                    case SearchFilterOperatorPolicy.CONTAIN:
                        sb.Append(string.Format(" and {0} like '%{1}%' ", f.Column, QuoteString(f.Value)));
                        break;
                    case SearchFilterOperatorPolicy.START_CONTAIN:
                        sb.Append(string.Format(" and {0} like '{1}%' ", f.Column, QuoteString(f.Value)));
                        break;
                    case SearchFilterOperatorPolicy.END_CONTAIN:
                        sb.Append(string.Format(" and {0} like '%{1}' ", f.Column, QuoteString(f.Value)));
                        break;
                    case SearchFilterOperatorPolicy.CN_CONTAIN:
                        sb.Append(string.Format(" and {0} like N'%{1}%' ", f.Column, QuoteString(f.Value)));
                        break;
                    case SearchFilterOperatorPolicy.CN_START_CONTAIN:
                        sb.Append(string.Format(" and {0} like N'{1}%' ", f.Column, QuoteString(f.Value)));
                        break;
                    case SearchFilterOperatorPolicy.CN_END_CONTAIN:
                        sb.Append(string.Format(" and {0} like N'%{1}' ", f.Column, QuoteString(f.Value)));
                        break;
                    case SearchFilterOperatorPolicy.CN_MULTIPLE:
                    case SearchFilterOperatorPolicy.CN_IN_RANGE:
                        sb.Append(string.Format(" and {0} in ({1}) ", f.Column, QuoteStringCNInRange(f.Values)));
                        break;
                    case SearchFilterOperatorPolicy.MULTIPLE:
                    case SearchFilterOperatorPolicy.IN_RANGE:
                        sb.Append(string.Format(" and {0} in ({1}) ", f.Column, QuoteStringInRange(f.Values)));
                        break;
                    case SearchFilterOperatorPolicy.NOT_IN_RANGE:
                        sb.Append(string.Format(" and {0} not in ({1}) ", f.Column, QuoteStringInRange(f.Values)));
                        break;
                    case SearchFilterOperatorPolicy.NUMBER_GREATER_THAN:
                        sb.Append(string.Format(" and {0} > {1} ", f.Column, QuoteNumber(f.Value)));
                        break;
                    case SearchFilterOperatorPolicy.NUMBER_GREATER_THAN_OR_EQUAL_TO:
                        sb.Append(string.Format(" and {0} >= {1} ", f.Column, QuoteNumber(f.Value)));
                        break;
                    case SearchFilterOperatorPolicy.NUMBER_LESS_THAN:
                        sb.Append(string.Format(" and {0} < {1} ", f.Column, QuoteNumber(f.Value)));
                        break;
                    case SearchFilterOperatorPolicy.NUMBER_LESS_THAN_OR_EQUAL_TO:
                        sb.Append(string.Format(" and {0} <= {1} ", f.Column, QuoteNumber(f.Value)));
                        break;
                    case SearchFilterOperatorPolicy.NUMBER_EQUAL_TO:
                        sb.Append(string.Format(" and {0} = {1} ", f.Column, QuoteNumber(f.Value)));
                        break;
                    case SearchFilterOperatorPolicy.BETWEEN:
                        if (!string.IsNullOrEmpty(f.Value) && !string.IsNullOrEmpty(f.Value1))
                            sb.Append(string.Format(" and {0} between {1} and {2}  ", f.Column, QuoteNumber(f.Value), QuoteNumber(f.Value1)));
                        if (!string.IsNullOrEmpty(f.Value) && string.IsNullOrEmpty(f.Value1))
                            sb.Append(string.Format(" and {0} >= {1} ", f.Column, QuoteNumber(f.Value)));
                        if (string.IsNullOrEmpty(f.Value) && !string.IsNullOrEmpty(f.Value1))
                            sb.Append(string.Format(" and {0} <= {1} ", f.Column, QuoteNumber(f.Value1)));
                        break;
                    case SearchFilterOperatorPolicy.DATE_BETWEEN:
                        if (!string.IsNullOrEmpty(f.Value) && !string.IsNullOrEmpty(f.Value1))
                            sb.Append(string.Format(" and {0} between '{1}' and '{2}'  ", f.Column, QuoteString(f.Value), Convert.ToDateTime(QuoteString(f.Value1)).AddDays(1).ToString("yyyy-MM-dd")));
                        if (!string.IsNullOrEmpty(f.Value) && string.IsNullOrEmpty(f.Value1))
                            sb.Append(string.Format(" and {0} >= '{1}' ", f.Column, QuoteString(f.Value)));
                        if (string.IsNullOrEmpty(f.Value) && !string.IsNullOrEmpty(f.Value1))
                            sb.Append(string.Format(" and {0} <= '{1}' ", f.Column, Convert.ToDateTime(QuoteString(f.Value1)).AddDays(1).ToString("yyyy-MM-dd")));
                        break;
                    case SearchFilterOperatorPolicy.DATETIME_BETWEEN:
                        if (!string.IsNullOrEmpty(f.Value) && !string.IsNullOrEmpty(f.Value1))
                            sb.Append(string.Format(" and {0} between '{1}' and '{2}'  ", f.Column, QuoteString(f.Value), Convert.ToDateTime(QuoteString(f.Value1)).AddSeconds(1).ToString("yyyy-MM-dd HH:mm:ss")));
                        if (!string.IsNullOrEmpty(f.Value) && string.IsNullOrEmpty(f.Value1))
                            sb.Append(string.Format(" and {0} >= '{1}' ", f.Column, QuoteString(f.Value)));
                        if (string.IsNullOrEmpty(f.Value) && !string.IsNullOrEmpty(f.Value1))
                            sb.Append(string.Format(" and {0} <= '{1}' ", f.Column, Convert.ToDateTime(QuoteString(f.Value1)).AddSeconds(1).ToString("yyyy-MM-dd HH:mm:ss")));
                        break;
                    case SearchFilterOperatorPolicy.DATE_GREATER_THAN:
                        sb.Append(string.Format(" and {0} > '{1}' ", f.Column, QuoteString(f.Value)));
                        break;
                    case SearchFilterOperatorPolicy.DATE_GREATER_THAN_OR_EQUAL_TO:
                        sb.Append(string.Format(" and {0} >= '{1}' ", f.Column, QuoteString(f.Value)));
                        break;
                    case SearchFilterOperatorPolicy.DATE_LESS_THAN:
                        sb.Append(string.Format(" and {0} < '{1}' ", f.Column, Convert.ToDateTime(QuoteString(f.Value)).AddDays(1).ToString("yyyy-MM-dd")));
                        break;
                    case SearchFilterOperatorPolicy.DATE_LESS_THAN_OR_EQUAL_TO:
                        sb.Append(string.Format(" and {0} <= '{1}' ", f.Column, QuoteString(f.Value)));
                        break;
                    case SearchFilterOperatorPolicy.DATE_EQUAL_TO:
                        sb.Append(string.Format(" and {0} = '{1}' ", f.Column, QuoteString(f.Value)));
                        break;
                }
            }

            return sb.ToString();
        }

        public static string QuoteStringCNInRange(string[] values)
        {
            if (values == null || values.Length == 0) return string.Empty;
            StringBuilder sb = new StringBuilder();

            foreach (string v in values)
            {
                sb.Append(string.Format(" N'{0}', ", QuoteString(v)));
            }

            return sb.ToString().Substring(0, sb.Length - 2);
        }

        public static string QuoteStringInRange(string[] values)
        {
            if (values == null || values.Length == 0) return string.Empty;
            StringBuilder sb = new StringBuilder();

            foreach (string v in values)
            {
                sb.Append(string.Format(" '{0}', ", QuoteString(v)));
            }

            return sb.ToString().Substring(0, sb.Length - 2);
        }

        public static string QuoteNumber(string s)
        {
            int i = 0;
            if (!int.TryParse(s, out i)) return "0";
            return s;
        }

        public static string QuoteString(string s)
        {
            if (s == null) s = string.Empty;

            return s.Replace("'", "''");// "'" + s.Replace("'", "''") + "'";
        }

    }

    public class GridColumnInfo
    {
        public string? title { get; set; }
        public string? dataIndex { get; set; }

        public int sequence { get; set; }
        public string? align { get; set; }
        public string? hidden { get; set; }
        public string? format { get; set; }

    }
}
