using System.Data;
using System.Text;
using IWS5.Core.Enums;
using IWS5.Core.Models.Processing;
using IWS5.Server.DataAccess;
using Microsoft.Data.SqlClient;
using ILogger = Serilog.ILogger;

namespace IWS5.Server.EventProcessors;

public class RuleProcessor(ILogger logger, IConfiguration configuration) : EventProcessor(logger, configuration)
{
    public override async Task<bool> ProcessEventAsync(EventModel eventData, int processId)
    {
        string sqlStr = "";
        try
        {
            using (var sqlConnection = new SqlConnection(ConnectionString))
            {
                await sqlConnection.OpenAsync();

                //Return True, False or Error

                //Get the SetRule records for the ProcessId and the EventId
                sqlStr = $"Select TOP (1) * from ATRule where processId = {processId} AND EventId = {eventData.CurrentEventId}";

                SqlDataAdapter dap3 = new SqlDataAdapter(sqlStr, sqlConnection);
                System.Data.DataSet ds3 = new System.Data.DataSet();
                dap3.Fill(ds3);

                int rowCnt3 = ds3.Tables[0].Rows.Count;
                if (rowCnt3 == 0)
                {
                    Logger.Error("No Rule records found in ProcessRule. WorkItemId: {WorkItemId}", eventData.WorkItemId);
                    return false;
                }

                string setRuleEventName = "";
                string setRuleType1 = "";
                string setRuleValue1 = "";
                string setRuleCompare = "";
                string setRuleType2 = "";
                string setRuleValue2 = "";

                foreach (DataRow tr in ds3.Tables[0].Rows)
                {
                    setRuleEventName = tr["EventName"].ToString();
                    setRuleType1 = tr["Type1"].ToString();
                    setRuleValue1 = tr["Value1"].ToString();
                    setRuleCompare = tr["Compare"].ToString();
                    setRuleType2 = tr["Type2"].ToString();
                    setRuleValue2 = tr["Value2"].ToString();
                }

                //*** Get the FROM value *******
                string compareValue1 = "";
                string compareValue2 = "";


                if (setRuleType1 == "Work Item Field")
                {
                    sqlStr = @"Select fieldValue from ATFieldInstanceString where WorkItemID = @workItemId AND FieldName = @fieldName 
                               UNION 
                               Select fieldValue from ATFieldInstanceOption where WorkItemID = @workItemId AND FieldName = @fieldName";
                    compareValue1 = Repository.GetRecordValue(sqlConnection, sqlStr, new Dictionary<string, object>{
                        {"@workItemId", eventData.WorkItemId},
                        {"@fieldName", setRuleValue1}
                    });
                }
                if (setRuleType2 == "Work Item Field")
                {
                    sqlStr = @"Select fieldValue from ATFieldInstanceString where WorkItemID = @workItemId AND FieldName = @fieldName 
                               UNION 
                               Select fieldValue from ATFieldInstanceOption where WorkItemID = @workItemId AND FieldName = @fieldName";
                    compareValue2 = Repository.GetRecordValue(sqlConnection, sqlStr, new Dictionary<string, object> { { "@setRuleValue2", setRuleValue2 } });
                }


                if (setRuleType1 == "Work Item Attribute")
                {
                    if (setRuleValue1 == "lastActionUser")
                    {
                        sqlStr = $"Select lastAction from ATWorkItemReference where WorkItemID = {eventData.WorkItemId}";
                        compareValue1 = Repository.GetRecordValue(sqlConnection, sqlStr);
                        if (compareValue1 != "")
                            compareValue1 = compareValue1.Substring(0, compareValue1.IndexOf(":"));
                    }
                    else
                    {
                        if (setRuleValue1 == "creator" || setRuleValue1 == "created" || setRuleValue1 == "Priority" ||
                            setRuleValue1 == "processId" || setRuleValue1 == "workItemName")
                        {
                            sqlStr = $"Select {setRuleValue1} from ATWorkItem where WorkItemID = {eventData.WorkItemId}";
                            compareValue1 = Repository.GetRecordValue(sqlConnection, sqlStr);
                        }
                        else
                        {
                            sqlStr = $"Select {setRuleValue1} from ATWorkItemReference where WorkItemID = {eventData.WorkItemId}";
                            compareValue1 = Repository.GetRecordValue(sqlConnection, sqlStr);
                        }
                    }
                }
                if (setRuleType2 == "Work Item Attribute")
                {
                    if (setRuleValue2 == "lastActionUser")
                    {
                        sqlStr = $"Select lastAction from ATWorkItemReference where WorkItemID = {eventData.WorkItemId}";
                        compareValue2 = Repository.GetRecordValue(sqlConnection, sqlStr);
                        if (compareValue2 != "")
                            compareValue2 = compareValue2.Substring(0, compareValue2.IndexOf(":"));
                    }
                    else
                    {
                        if (setRuleValue2 == "creator" || setRuleValue2 == "created" || setRuleValue2 == "Priority" ||
                            setRuleValue2 == "processId" || setRuleValue2 == "workItemName")
                        {
                            sqlStr = $"Select {setRuleValue2} from ATWorkItem where WorkItemID = {eventData.WorkItemId}";
                            compareValue2 = Repository.GetRecordValue(sqlConnection, sqlStr);
                        }
                        else
                        {
                            sqlStr = $"Select {setRuleValue2} from ATWorkItemReference where WorkItemID = {eventData.WorkItemId}";
                            compareValue2 = Repository.GetRecordValue(sqlConnection, sqlStr);
                        }
                    }
                }

                if (setRuleType2 == "Text")
                {
                    compareValue2 = setRuleValue2;
                }


                if (compareValue1 == "" || compareValue2 == "")
                {
                    var detailBuilder = new StringBuilder();
                    detailBuilder.AppendLine($"setRuleType1: {setRuleType1}");
                    detailBuilder.AppendLine($"setRuleValue1: {setRuleValue1}");
                    detailBuilder.AppendLine($"setRuleCompare: {setRuleCompare}");
                    detailBuilder.AppendLine($"setRuleType2: {setRuleType2}");
                    detailBuilder.AppendLine($"setRuleValue2: {setRuleValue2}");

                    Logger.Error("No value retrieved in ProcessRule for work item {WorkItemId}. SQL: {Sql}. Details: {Details}", eventData.WorkItemId, sqlStr, detailBuilder.ToString());
                    return false;
                }

                var actionDecision = false;

                switch (setRuleCompare)
                {
                    case "=":
                    {
                        actionDecision = compareValue1 == compareValue2;
                        break;
                    }
                    case "Not Equal":
                    {
                        actionDecision = compareValue1 != compareValue2;
                        break;
                    }
                    default:
                    {
                        var isFirstNumeric = Double.TryParse(Convert.ToString(compareValue1),
                            System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo,
                            out _);

                        var isSecondNumeric = Double.TryParse(Convert.ToString(compareValue2),
                            System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo,
                            out _);

                        if (isFirstNumeric && isSecondNumeric)
                        {
                            Int32 compareInt1 = Convert.ToInt32(compareValue1);
                            Int32 compareInt2 = Convert.ToInt32(compareValue2);

                            switch (setRuleCompare)
                            {
                                case ">":
                                    actionDecision = compareInt1 > compareInt2;
                                    break;
                                case "<":
                                    actionDecision = compareInt1 < compareInt2;
                                    break;
                                case "<=":
                                    actionDecision = compareInt1 <= compareInt2;
                                    break;
                                case ">=":
                                    actionDecision = compareInt1 >= compareInt2;
                                    break;
                            }
                        }
                        else
                        {
                            Logger.Error("Compare values {0} or {1} are not numeric in ProcessRule in event {2} workItem {3}", compareValue1, compareValue2, eventData.CurrentEventId, eventData.WorkItemId);
                            return false;
                        }

                        break;
                    }
                }

                sqlStr = "SELECT NextEventId FROM ATEventDefinition With (NoWait) where ProcessId = @currentProcessID AND EventName = @currentEventName And EventTypeId = 14 And Action = @actionDecision";
                var decisionEventId = Repository.GetRecordValue(sqlConnection, sqlStr, new Dictionary<string, object>
                {
                    { "@currentProcessID", processId },
                    { "@currentEventName", eventData.CurrentEventName },
                    { "@actionDecision", actionDecision }
                });

                sqlStr =
                    $@"Update ATWorkItemReference 
                       SET EventID = {decisionEventId}, 
                           ServerRequest = {(int)ServerRequest.ForwardExistingWorkItem}, 
                           ServerRequestParam = NULL, 
                           LastActionDate = '{DateTime.Now}', 
                           SourceQueueId = NULL 
                       WHERE WorkItemID = {eventData.WorkItemId}";

                SqlCommand cmd2 = new SqlCommand(sqlStr, sqlConnection);
                await cmd2.ExecuteNonQueryAsync();
                return true;
            }
        }
        catch (Exception ex)
        {
            Logger.Error("An error occurred in ProcessRule: event {0} workItem {1}: {2}", eventData.CurrentEventId, eventData.WorkItemId, ex.Message);
            return false;
        }
    }
}