using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Sockeye.Util;
using Sockeye.Api.ControllerHelpers;
using Sockeye.Models;
using Sockeye.DataList;


namespace Sockeye.Biz
{


    internal class DataListColumnViewBiz : BizObject
    {

        internal DataListColumnViewBiz(AyContext dbcontext, long currentUserId, long userTranslationId, AuthorizationRoles UserRoles)
        {
            ct = dbcontext;
            UserId = currentUserId;
            UserTranslationId = userTranslationId;
            CurrentUserRoles = UserRoles;
            BizType = SockType.DataListColumnView;
        }

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



        ////////////////////////////////////////////////////////////////////////////////////////////////
        //EXISTS 
        internal async Task<bool> ExistsAsync(long id)
        {
            return await ct.DataListColumnView.AnyAsync(z => z.Id == id);
        }


        ////////////////////////////////////////////////////////////////////////////////////////////////
        //CREATE   
        // 
        internal async Task<DataListColumnView> CreateAsync(DataListColumnView newObject)
        {
            ValidateAsync(newObject);
            if (HasErrors)
                return null;
            else
            {
                //delete the existing one in favor of this one
                var dbObject = await GetAsync(newObject.UserId, newObject.ListKey, false);
                if (dbObject != null)
                {
                    ct.DataListColumnView.Remove(dbObject);
                    await ct.SaveChangesAsync();
                }

                await ct.DataListColumnView.AddAsync(newObject);
                await ct.SaveChangesAsync();

                return newObject;
            }
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////
        //SET SORT   
        // 

        internal async Task<bool> SetSort(Sockeye.Models.DataListSortRequest newObject)
        {
            //Get the current column view (in an updateable manner) and update it's sort property and save
            var dbObject = await ct.DataListColumnView.SingleOrDefaultAsync(z => z.UserId == UserId && z.ListKey == newObject.ListKey);
            if (dbObject == null)
                dbObject = await CreateDefaultColumnView(newObject.ListKey);
            //convert arrays to proper format for saving
            Dictionary<string, string> newSort = new Dictionary<string, string>();
            for (int x = 0; x < newObject.sortBy.Length; x++)
                newSort.Add(newObject.sortBy[x], (newObject.sortDesc[x] ? "-" : "+"));
            dbObject.Sort = JsonConvert.SerializeObject(newSort);
            //columnview is always replace
            await ct.SaveChangesAsync();
            return true;
        }




        ////////////////////////////////////////////////////////////////////////////////////////////////
        //GET 
        //
        //
        internal async Task<DataListColumnView> GetAsync(long userId, string listKey, bool createDefaultIfNecessary)
        {
            var ret = await ct.DataListColumnView.AsNoTracking().SingleOrDefaultAsync(z => z.UserId == userId && z.ListKey == listKey);
            if (ret == null && createDefaultIfNecessary)
            {
                return await CreateDefaultColumnView(listKey);
            }
            return ret;
        }

        internal async Task<DataListColumnView> CreateDefaultColumnView(string listKey)
        {
            if (!DataListFactory.ListKeyIsValid(listKey))
            {
                throw new System.ArgumentOutOfRangeException($"ListKey '{listKey}' is not a valid DataListKey");
            }
            var ret = new DataListColumnView();
            ret.UserId = UserId;
            ret.ListKey = listKey;
            var dataList = DataListFactory.GetAyaDataList(listKey, 0);
            ret.Columns = JsonConvert.SerializeObject(dataList.DefaultColumns);
            ret.Sort = JsonConvert.SerializeObject(dataList.DefaultSortBy);
            return await CreateAsync(ret);
        }





        ////////////////////////////////////////////////////////////////////////////////////////////////
        //DELETE (RESET)
        //
        internal async Task<DataListColumnView> DeleteAsync(long userId, string listKey)
        {
            //this is effectively the RESET route handler
            //so it can be called any time even if there is no default list and it's a-ok
            //because a new default will be created if needed

            var dbObject = await GetAsync(userId, listKey, false);
            if (dbObject != null)
            {
                ct.DataListColumnView.Remove(dbObject);
                await ct.SaveChangesAsync();
                dbObject = await GetAsync(userId, listKey, true);
            }
            return dbObject;
        }


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

        //Can save or update?
        private void ValidateAsync(DataListColumnView inObj)
        {

            if (inObj.UserId != UserId)
                AddError(ApiErrorCode.NOT_AUTHORIZED, "UserId", "Only own view can be modified");

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

            if (!DataListFactory.ListKeyIsValid(inObj.ListKey))
                AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "ListKey", $"ListKey \"{inObj.ListKey}\" DataListKey is not valid");


            //Validate Sort JSON
            try
            {
                JsonConvert.DeserializeObject<Dictionary<string, string>>(inObj.Sort);
            }
            catch (System.Exception ex)
            {
                AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Sort", "Sort is not valid JSON string, can't convert to valid Dictionary<string, string> SortBy, error: " + ex.Message);
            }

            //Validate Columns JSON
            try
            {

                JsonConvert.DeserializeObject<List<string>>(inObj.Columns);
            }
            catch (System.Exception ex)
            {
                AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Sort", "Sort is not valid JSON string, can't convert to valid Dictionary<string, string> SortBy, error: " + ex.Message);
            }

            return;
        }



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

    }//eoc


}//eons

