using Microsoft.Ajax.Utilities;
using NLog;
using NLog.Config;
using ProfitGroup.Rdnl.Extensions;
using ProfitGroup.SampleService.Models;
using RnD.API;
using RnD.BusinessLayer.EF.Interfaces;
using RnD.BusinessLayer.Interfaces.ExtensionMethods;
using RnD.BusinessLayer.Interfaces.InfoField;
using RnD.BusinessLayer.Interfaces.Model;
using RnD.Model.EF;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Validation;
using System.IO;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using RnD.Model;

namespace ProfitGroup.SampleService.Core.Services
{
    public class SampleService : ISampleService
    {
        private RnDConnection _databaseContext;
        private readonly RDnLManager _manager;
        private readonly API _api;
        private readonly SampleConfirmationService _sampleConfirmationService;

        private ILogger Logger
        {
            get
            {
                var loggerConfig = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "nlog.config");
                LogManager.Setup().LoadConfigurationFromFile(loggerConfig);
                LogManager.Configuration = new XmlLoggingConfiguration(loggerConfig);

                return LogManager.GetCurrentClassLogger();
            }
        }

        public SampleService(RDnLManager manager, API api, SampleConfirmationService sampleConfirmationService)
        {
            _manager = manager;
            _api = api;
            _sampleConfirmationService = sampleConfirmationService;
            _databaseContext = ((ISession<RnDConnection>)manager.EventAwareObjectFactory.FactorySession).Context;
        }


        public IEnumerable<TaskFilterDTO> GetTaskKeys(string plantName, string operationControlName,
            string packageOrStage)
        {
            var task = _api.BusinessObjectFactory.TaskTypes.GetAllTaskTypes()
                .FirstOrDefault(c => c.Description == "Sample Creation");

            var tasks = _databaseContext.RndvTk.Join(_databaseContext.RndvTkDetails,
                    g => g.TK,
                    taskDetail => taskDetail.TK,
                    (taskEntity, taskDetail) => new { Task = taskEntity, TaskDetail = taskDetail })
                .Where(c => c.Task.TK_TP == task.TaskType
                            && c.Task.ACTIVE_STR == "1"
                            && c.Task.VERSION == c.TaskDetail.VERSION)
                .Select(c => c.TaskDetail)
                .ToList()
                .GroupBy(c => c.TK);

            var creationTasks = tasks.Where(c =>
                c.FirstOrDefault(taskEntity => taskEntity.DEF_VAL == plantName) != null
                && c.FirstOrDefault(taskEntity => taskEntity.DEF_VAL == operationControlName) != null);

            if (creationTasks.Count() > 1)
            {
                if (string.IsNullOrEmpty(packageOrStage))
                {
                    creationTasks =
                        creationTasks.Where(c =>
                            c.FirstOrDefault(attribute => attribute.COL_ID == "38") == null); // Ищем тот таск, у которого отсутствует стадия
                }
                else
                {
                    creationTasks =
                        creationTasks.Where(c =>
                            c.FirstOrDefault(attribute => attribute.COL_ID == "38") != null); // Ищем тот таск, у которого имеется стадия
                }
            }

            if (creationTasks.Count() > 1)
            {
                if (!string.IsNullOrEmpty(packageOrStage))
                {
                    creationTasks = creationTasks.Where(c =>
                        c.FirstOrDefault(attribute => attribute.DEF_VAL == packageOrStage) != null);
                }
            }

            var creationTask = creationTasks.SingleOrDefault();

            if (creationTask == null)
            {
                return Enumerable.Empty<TaskFilterDTO>();
            }

            var taskObject =
                _api.BusinessObjectFactory.TaskDefinition.GetActiveVersion(task.TaskType, creationTask.Key);

            // var taskKeys = _api.BusinessObjectFactory.TaskKeys.GetAll(task.TaskType, (decimal)taskObject.ID,
            //     (decimal)taskObject.Version);

            var taskKeys = _databaseContext.RndvTkDetails.Where(c =>
                c.TK == (decimal)taskObject.ID
                && c.VERSION == (decimal)taskObject.Version
            ).ToList();


            return taskKeys.Select(c => new TaskFilterDTO
            {
                Field = $"{c.COL_ID}@{c.COL_TP}",
                Operator = c.OPERAT,
                Value = c.DEF_VAL,
                Sequence = c.SEQ
            });


            //var task = _api.BusinessObjectFactory.TaskTypes.GetAllTaskTypes()
            //    .FirstOrDefault(c => c.Description == "Sample Creation");


            //var tasks = _databaseContext.RndvTk.Join(_databaseContext.RndvTkDetails,
            //        task => task.TK,
            //        taskDetail => taskDetail.TK,
            //        (task, taskDetail) => new { Task = task, TaskDetail = taskDetail })
            //    .Where(c => c.Task.TK_TP == task.TaskType
            //                && c.Task.ACTIVE_STR == "1"
            //                && c.Task.VERSION == c.TaskDetail.VERSION
            //                && c.TaskDetail.DEF_VAL_MAIN == plantName
            //                && c.Task.DESCRIPTION_MAIN.Contains(operationControlName))
            //    .ToList();

            //var creationTask = tasks.SingleOrDefault();

            //if (creationTask == null)
            //{
            //    return Enumerable.Empty<TaskFilterDTO>();
            //}

            //var taskObject =
            //    _api.BusinessObjectFactory.TaskDefinition.GetActiveVersion(task.TaskType, creationTask.Task.TK);

            //var taskKeys = _api.BusinessObjectFactory.TaskKeys.GetAll(task.TaskType, (decimal)taskObject.ID,
            //    (decimal)taskObject.Version);

            //return taskKeys.Select(c => new TaskFilterDTO
            //{
            //    Field = $"{c.ColumnID}@{c.ColumnType}",
            //    Operator = c.Operator,
            //    Value = c.DefaultValue,
            //    Sequence = c.Sequence
            //});
        }

        public void FillSampleInfoCards(Sample sample, List<InfoCardSetting> infoFieldInfoElements, string plantName)
        {
            var material = sample.Attributes.FirstOrDefault(c => c.ShortDescription == "Product");
            var productValue = material?.Value ?? string.Empty;

            foreach (var infoFieldInfo in infoFieldInfoElements)
            {
                if (infoFieldInfo.Plant == null)
                {

                    foreach (var infoFieldPath in infoFieldInfo.InfoFieldPaths)
                    {
                        IEnumerable<RnD.Model.IInfoField> infoFields = Enumerable.Empty<RnD.Model.IInfoField>();

                        if (infoFieldPath.InfoCard == null)
                        {
                            infoFields = sample.InfoCards
                                .SelectMany(c => c.InfoFields)
                                .Where(g => g.ShortDescription == infoFieldPath.InfoField);
                        }else
                        {
                            infoFields = sample.InfoCards
                                .Where(c => c.ShortDescription == infoFieldPath.InfoCard)
                                .SelectMany(c => c.InfoFields)
                                .Where(g => g.ShortDescription == infoFieldPath.InfoField);
                        }

                        if (infoFields.Any())
                        {
                            foreach (var infoField in infoFields)
                            {
                                // Строгая проверка (Ограничение только для даты)
                                if (infoFieldInfo.Name == "CreateDate")
                                {
                                    if (productValue.StartsWith("FP") && infoField.ShortDescription == "S4_ProdManufDate")
                                    {
                                        infoField.InfoFieldValue = infoFieldInfo.Value;
                                        continue;
                                    }

                                    if (productValue.StartsWith("FP") && infoField.ShortDescription == "ProdManufacturDate")
                                    {
                                        infoField.InfoFieldValue = infoFieldInfo.Value;
                                        continue;
                                    }

                                    if (productValue.StartsWith("RM") && infoField.ShortDescription == "S4_RawMatManufDate")
                                    {
                                        infoField.InfoFieldValue = infoFieldInfo.Value;
                                        continue;
                                    }

                                    if (productValue.StartsWith("RM") && infoField.ShortDescription == "RawMatManufactDate")
                                    {
                                        infoField.InfoFieldValue = infoFieldInfo.Value;
                                        continue;
                                    }

                                    continue;
                                }

                                infoField.InfoFieldValue = infoFieldInfo.Value;
                            }
                        }else
                        {
                            Logger.Error(
                           $@"Переданный атрибут '{infoFieldInfo.Name}' не был никуда записан. Не нашлось ни одной инфокарты и соответствующего инфополя из настроек appsettings.json");


                        }



                    }


                }
                else if (infoFieldInfo.Plant == plantName)
                {
                    RnD.Model.IInfoField infoField = null;
                    int writeCount = 0;

                    foreach (var infoFieldPath in infoFieldInfo.InfoFieldPaths)
                    {
                        var infoCard = sample.InfoCards
                            .FirstOrDefault(c => c.ShortDescription == infoFieldPath.InfoCard);

                        infoField = infoCard?.InfoFields
                            .FirstOrDefault(c => c.ShortDescription == infoFieldPath.InfoField);

                        if (infoField != null)
                        {
                            // Ограничение только для даты
                            if (infoFieldInfo.Name == "CreateDate")
                            {
                                if (productValue.StartsWith("FP") && infoField.ShortDescription == "S4_ProdManufDate")
                                {
                                    infoField.InfoFieldValue = infoFieldInfo.Value;
                                    ++writeCount;
                                    continue;
                                }

                                if (productValue.StartsWith("FP") && infoField.ShortDescription == "ProdManufacturDate")
                                {
                                    infoField.InfoFieldValue = infoFieldInfo.Value;
                                    ++writeCount;
                                    continue;
                                }

                                if (productValue.StartsWith("RM") && infoField.ShortDescription == "S4_RawMatManufDate")
                                {
                                    infoField.InfoFieldValue = infoFieldInfo.Value;
                                    ++writeCount;
                                    continue;
                                }

                                if (productValue.StartsWith("RM") && infoField.ShortDescription == "RawMatManufactDate")
                                {
                                    infoField.InfoFieldValue = infoFieldInfo.Value;
                                    ++writeCount;
                                    continue;
                                }

                                continue;
                            }

                            infoField.InfoFieldValue = infoFieldInfo.Value;
                            ++writeCount;
                        }
                    }

                    if (writeCount == 0)
                    {
                        //Logger.Error($@"Переданный атрибут '{infoFieldInfo.Name}' не был никуда записан. Не нашлось ни одной инфокарты и соответствующего инфополя из настроек Appsetting.json");
                        continue;
                    }
                }
            }


            // foreach (var infoFieldInfo in infoFieldInfoElements)
            // {
            //     var infoFields = sample.InfoCards
            //         .SelectMany(c => c.InfoFields)
            //         .Where(c => c.ShortDescription == infoFieldInfo.InfoField);
            //
            //     foreach (var infoField in infoFields)
            //         infoField.InfoFieldValue = infoFieldInfo.Value;
            // }


            //foreach (var infoCard in infoCards)
            //{
            //    var searchedCard = sample.InfoCards.FirstOrDefault(c => c.ShortDescription == infoCard.InfoCard);

            //    if (searchedCard == null)
            //    {
            //        Logger.Error(
            //            $@"Проба {sample.ShortDescription}:{sample.ID}. Инфокарта shortDesc: ""{infoCard.InfoCard}"" не найдена. Запись данных на инфополе отменено!");
            //        continue;
            //    }

            //    var infoField =
            //        searchedCard.InfoFields.FirstOrDefault(c => c.ShortDescription == infoCard.InfoField);

            //    if (infoField == null)
            //    {
            //        Logger.Error(
            //            $@"Проба {sample.ShortDescription}:{sample.ID}. Инфокарта shortDesc: ""{infoCard.InfoCard}"". Инфополе ""{infoCard.InfoField}"" не найдено. Запись данных на данное инфополе отменено!");
            //        continue;
            //    }

            //    infoField.InfoFieldValue = infoCard.Value;
            //}

            _api.BusinessObjectFactory.SaveChanges();
        }

        public async Task<bool> ValidateSample(string shortDescription)
        {
            if (string.IsNullOrEmpty(shortDescription))
                return false;

            var sample = await _databaseContext.RndvSc.FirstOrDefaultAsync(c => c.SC_VALUE == shortDescription);

            if (sample == null)
                return false;

            return true; // Создан
        }

        public async Task SendConfirmation(MT_InspLot request, SampleFullDTO sampleFullDto, string message = null)
        {
            var sampleIsCreated = await ValidateSample(sampleFullDto?.ShortDescription);

            (bool isSuccess, System.Net.HttpStatusCode statusCode, string message) sampleIsConfirmed = default;

            try
            {
                sampleIsConfirmed = await _sampleConfirmationService
                    .SendConfirmationToSap(request, sampleFullDto, sampleIsCreated, message);
            }
            catch (Exception ex)
            {
                Logger.Log(LogLevel.Error, string.Concat(ex.Message, "\n", ex.StackTrace));
            }

            var requestMessageBuilder = new StringBuilder();

            requestMessageBuilder.Append(sampleIsCreated
                ? $@"Проба ""{sampleFullDto.ShortDescription}"" успешно сформирована. "
                : $@"Проба не сформирована. ");

            requestMessageBuilder.Append(sampleIsConfirmed.isSuccess
                ? $"Был отправлен Confirmation в SAP/S4. Получен успешный HttpStatus {sampleIsConfirmed.statusCode} ({(int)sampleIsConfirmed.statusCode}), \n {message}"
                : $"Был отправлен Confirmation в SAP/S4. Получен ошибочный HttpStatus {sampleIsConfirmed.statusCode} ({(int)sampleIsConfirmed.statusCode}), \n {message}");

            Logger.Log(LogLevel.Info, requestMessageBuilder.ToString());
        }
    }
}