using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Sockeye.Util;
using Sockeye.Api.ControllerHelpers;
using Sockeye.Models;


namespace Sockeye.Biz
{


    internal class UserOptionsBiz : BizObject
    {

        internal UserOptionsBiz(AyContext dbcontext, long currentUserId, AuthorizationRoles userRoles)
        {
            ct = dbcontext;
            UserId = currentUserId;
            CurrentUserRoles = userRoles;
            BizType = SockType.UserOptions;
        }


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

        //Get one
        internal async Task<UserOptions> GetAsync(long fetchId)
        {
            //NOTE: get by UserId as there is a 1:1 relationship, not by useroptions id
            //This is simple so nothing more here, but often will be copying to a different output object or some other ops
            return await ct.UserOptions.SingleOrDefaultAsync(z => z.UserId == fetchId);
        }


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

        //Creating a user creates a user options so no need for create ever

        // ////////////////////////////////////////////////////////////////////////////////////////////////
        // //CREATE   
        // //
        // internal async Task<UserOptions> CreateAsync(UserOptions newObject)
        // {

        //     User u = await ct.User.AsNoTracking().SingleOrDefaultAsync(z => z.Id == newObject.UserId);
        //     if (u == null)
        //     {
        //         AddError(ApiErrorCode.NOT_FOUND, "id");
        //         return null;
        //     }
        //     //Also used for Contacts (customer type user or ho type user)
        //     //by users with no User right but with Customer rights so need to double check here
        //     if (
        //         (u.IsOutsideUser && !Authorized.HasModifyRole(CurrentUserRoles, SockType.Customer)) ||
        //         (!u.IsOutsideUser && !Authorized.HasModifyRole(CurrentUserRoles, SockType.User))
        //         )
        //     {
        //         AddError(ApiErrorCode.NOT_AUTHORIZED);
        //         return null;
        //     }

        //     Validate(newObject);
        //     if (HasErrors)
        //         return null;
        //     else
        //     {

        //         await ct.UserOptions.AddAsync(newObject);
        //         await ct.SaveChangesAsync();
        //         await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct);

        //         return newObject;
        //     }
        // }


        //put
        internal async Task<bool> PutAsync(UserOptions dbObject, UserOptions inObj)
        {

            //if it's not the user's own options then we need to check it just as for User / Contact objects
            if (dbObject.Id != UserId)
            {
                User u = await ct.User.AsNoTracking().SingleOrDefaultAsync(z => z.Id == dbObject.Id);
                if (u == null)
                {
                    AddError(ApiErrorCode.NOT_FOUND, "id");
                    return false;
                }
                //Also used for Contacts (customer type user or ho type user)
                //by users with no User right but with Customer rights so need to double check here
                if (
                    (u.IsOutsideCustomerContactTypeUser && !Authorized.HasModifyRole(CurrentUserRoles, SockType.Customer)) ||
                    (!u.IsOutsideCustomerContactTypeUser && !Authorized.HasModifyRole(CurrentUserRoles, SockType.User))
                    )
                {
                    AddError(ApiErrorCode.NOT_AUTHORIZED);
                    return false;
                }
            }

            //Replace the db object with the PUT object
            CopyObject.Copy(inObj, dbObject, "Id, UserId");
            //Set "original" value of concurrency token to input token
            //this will allow EF to check it out
            //BUT NOT IF IT"S FROM A DUPLICATION OP (CONCURRENCY=0)
            if (inObj.Concurrency != 0)
                ct.Entry(dbObject).OriginalValues["Concurrency"] = inObj.Concurrency;

            Validate(dbObject);
            if (HasErrors)
                return false;

            await ct.SaveChangesAsync();
            //Log
            await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, SockType.User, SockEvent.Modified), ct);
            return true;
        }


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

        //Can save or update?
        private void Validate(UserOptions inObj)
        {
            //UserOptions is never new, it's created with the User object so were only here for an edit

            //UserId required
            if (inObj.UserId == 0)
                AddError(ApiErrorCode.VALIDATION_REQUIRED, "UserId");


            //Hexadecimal notation: #RGB[A] R (red), G (green), B (blue), and A (alpha) are hexadecimal characters (0–9, A–F). A is optional. The three-digit notation (#RGB) is a shorter version of the six-digit form (#RRGGBB). For example, #f09 is the same color as #ff0099. Likewise, the four-digit RGB notation (#RGBA) is a shorter version of the eight-digit form (#RRGGBBAA). For example, #0f38 is the same color as #00ff3388.
            if (inObj.UiColor.Length > 12 || inObj.UiColor.Length < 4 || inObj.UiColor[0] != '#')
            {
                AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "UiColor", "UiColor must be valid HEX color value");
            }

            return;
        }



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

    }//eoc


}//eons

