using System.Linq;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json.Linq;
using AyaNova.Util;
using AyaNova.Api.ControllerHelpers;
using AyaNova.Models;
using AyaNova.PickList;

namespace AyaNova.Biz
{


    internal class PickListBiz : BizObject
    {

        internal PickListBiz(AyContext dbcontext, long currentUserId, long userTranslationId, AuthorizationRoles UserRoles)
        {
            ct = dbcontext;
            UserId = currentUserId;
            UserTranslationId = userTranslationId;
            CurrentUserRoles = UserRoles;
            BizType = AyaType.PickListTemplate;
        }

        internal static PickListBiz GetBiz(AyContext ct, Microsoft.AspNetCore.Http.HttpContext httpContext = null)
        {
            if (httpContext != null)
                return new PickListBiz(ct, UserIdFromContext.Id(httpContext.Items), UserTranslationIdFromContext.Id(httpContext.Items), UserRolesFromContext.Roles(httpContext.Items));
            else
                return new PickListBiz(ct, 1, ServerBootConfig.AYANOVA_DEFAULT_TRANSLATION_ID, AuthorizationRoles.BizAdminFull);
        }




        ////////////////////////////////////////////////////////////////////////////////////////////////
        /// GET

        //Get one
        internal async Task<PickListTemplate> GetAsync(AyaType ayaType, bool logTheGetEvent = true)
        {
            long lTypeId = (long)ayaType;

            //first try to fetch from db
            var ret = await ct.PickListTemplate.SingleOrDefaultAsync(z => z.Id == lTypeId);
            if (logTheGetEvent && ret != null)
            {
                //Log
                await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, lTypeId, BizType, AyaEvent.Retrieved), ct);
            }

            //not in db then get the default
            if (ret == null)
            {
                var PickList = PickListFactory.GetAyaPickList(ayaType);
                if (PickList != null)
                {
                    ret = new PickListTemplate();
                    ret.Id = lTypeId;
                    ret.Template = PickList.DefaultTemplate;
                }
            }
            return ret;
        }




        //get picklist 
        internal async Task<List<NameIdActiveItem>> GetPickListAsync(IAyaPickList PickList, string query, bool inactive, long preId, ILogger log)
        {

            //Crack and validate the query part set a broken rule if not valid and return null
            //else do the query
            string TagSpecificQuery = null;
            string AutoCompleteQuery = null;

            //Here need to handle scenario of badly formed query so user knows they did it wrong and doesn't just assume it's not there
            //determine if this is a tag query and extract it
            bool HasQuery = !string.IsNullOrWhiteSpace(query);
            if (HasQuery)
            {
                AutoCompleteQuery = query;
                //is it a dual template and tag query?
                if (AutoCompleteQuery.Contains(" "))
                {
                    // split the query on space
                    var querySegments = AutoCompleteQuery.Split(' ');
                    if (querySegments.Length > 2)
                    {
                        AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "query", "LT:ErrorPickListQueryInvalid");
                        return null;
                    }
                    //check the two query segments, it's valid for the user to put the tag first or the template query first
                    //we handle either way, but if there are no tas in either then it's not a valid query
                    if (querySegments[0].Contains(".."))
                    {
                        TagSpecificQuery = querySegments[0].Replace("..", "");
                        AutoCompleteQuery = querySegments[1];
                    }
                    else if (querySegments[1].Contains(".."))
                    {
                        TagSpecificQuery = querySegments[1].Replace("..", "");
                        AutoCompleteQuery = querySegments[0];
                    }
                    else
                    {
                        AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "query", "LT:ErrorPickListQueryInvalid");
                        return null;
                    }

                }
                else
                {
                    //is it a tag only query?
                    if (AutoCompleteQuery.Contains(".."))
                    {
                        TagSpecificQuery = AutoCompleteQuery.Replace("..", "");
                        AutoCompleteQuery = null;
                    }

                }
            }

            //Final fixup if user specifies tag query but there are not tags on this object then
            //rather than error just accept it as a no tag query
            //Note: it's not valid to have more than one field with tags in the picklist definition so this works
            if (PickList.ColumnDefinitions.FirstOrDefault(z => z.ColumnDataType == UiFieldDataType.Tags) == null)
            {
                TagSpecificQuery = null;
            }

            //Autocomplete and tagonly query terms now set for consumption by PickListFetcher, ready to fetch...
            List<NameIdActiveItem> items = await PickListFetcher.GetResponseAsync(PickList, AutoCompleteQuery, TagSpecificQuery, inactive, preId, ct, log);
            return items;
        }


        //get picklist templates, basically all the object types that support picklists
        internal List<NameIdItem> GetListOfAllPickListTypes(long translationId)
        {
            return PickListFactory.GetListOfAllPickListTypes(translationId);
        }




        ////////////////////////////////////////////////////////////////////////////////////////////////
        //UPDATE
        //

        //put
        internal async Task<bool> ReplaceAsync(PickListTemplate template)
        {
            var o = await ct.PickListTemplate.FirstOrDefaultAsync(z => z.Id == (long)template.Id);
            bool bAdd = false;
            if (o == null)
            {
                o = new PickListTemplate();
                bAdd = true;
            }
            o.Id = (long)template.Id;
            o.Template = template.Template;


            Validate(o);
            if (HasErrors)
                return false;
            if (bAdd)
                await ct.PickListTemplate.AddAsync(o);
                
            await ct.SaveChangesAsync();

            //Log modification and save context
            await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, o.Id, BizType, AyaEvent.Modified), ct);



            return true;
        }


        ////////////////////////////////////////////////////////////////////////////////////////////////
        //DELETE (return to default template)
        //
        internal async Task<bool> DeleteAsync(AyaType ayaType)
        {
            //REMOVE ANY RECORD WITH SAME AYATYPE ID
            long lTypeId = (long)ayaType;

            var o = await ct.PickListTemplate.FirstOrDefaultAsync(z => z.Id == lTypeId);
            if (o != null)
            {
                ct.PickListTemplate.Remove(o);
                await ct.SaveChangesAsync();
                //Event log process delete
                await EventLogProcessor.DeleteObjectLogAsync(UserId, BizType, lTypeId, ayaType.ToString(), ct);
            }

            return true;
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////
        //VALIDATION
        //

        //Can save or update?
        private void Validate(PickListTemplate inObj)
        {

            //validate that the template is valid, the type is legit etc
            var TemplateType = (AyaType)inObj.Id;
            if (!TemplateType.HasAttribute(typeof(CoreBizObjectAttribute)))
            {
                AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "ayaType", "AyaType specified is not a Core object type and doesn't support pick list templates");
                return;
            }


            if (string.IsNullOrWhiteSpace(inObj.Template))
                AddError(ApiErrorCode.VALIDATION_REQUIRED, "Template");

            var PickList = PickListFactory.GetAyaPickList(TemplateType);

            //Filter json must parse
            //this is all automated normally so not going to do too much parsing here
            //just ensure it's basically there
            if (!string.IsNullOrWhiteSpace(inObj.Template))
            {
                try
                {
                    var v = JArray.Parse(inObj.Template);
                    for (int i = 0; i < v.Count; i++)
                    {
                        var filterItem = v[i];
                        if (filterItem["fld"] == null)
                            AddError(ApiErrorCode.VALIDATION_REQUIRED, "Template", $"Template array item {i}, object is missing required \"fld\" property ");
                        else
                        {
                            var fld = filterItem["fld"].Value<string>();
                            if (string.IsNullOrWhiteSpace(fld))
                                AddError(ApiErrorCode.VALIDATION_REQUIRED, "Template", $"Template array item {i}, \"fld\" property is empty and required");

                            //validate the field name if we can
                            if (PickList != null)
                            {

                                var TheField = PickList.ColumnDefinitions.SingleOrDefault(z => z.FieldKey.ToLowerInvariant() == fld);

                                if (TheField == null)
                                {
                                    AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Template", $"Template array item {i}, fld property value \"{fld}\" is not a valid value for AyaType specified");
                                }

                            }
                        }

                    }
                }
                catch (Newtonsoft.Json.JsonReaderException ex)
                {
                    AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Template", "Template is not valid JSON string: " + ex.Message);

                }
            }
        }




        /////////////////////////////////////////////////////////////////////

    }//eoc


}//eons

