using System.Linq;
using Hims.Shared.UserModels.Common;

namespace Hims.Api.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Domain.Services;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Shared.UserModels.Menu;
    using Relationship = Shared.UserModels.Menu.Relationship;
    using Button = Shared.UserModels.Menu.Button;
    using Utilities;
    using Hims.Shared.EntityModels;
    using Hims.Shared.Library.Enums;
    using Hims.Api.Models;

    /// <inheritdoc />
    [Authorize]
    [Route("api/menu")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class MenuController : BaseController
    {
        /// <summary>
        /// The coupon services.
        /// </summary>
        private readonly IMenuService service;

        /// <summary>
        /// The auditlog services.
        /// </summary>
        private readonly IAuditLogService auditLogServices;

        /// <inheritdoc />
        public MenuController(IMenuService service, IAuditLogService auditLogServices)
        {
            this.service = service;
            this.auditLogServices = auditLogServices;
        }

        /// <summary>
        /// The fetch coupons.
        /// </summary>
        /// <param name="model">
        /// The coupon filter model.
        /// </param>
        /// <returns>
        /// The list of coupons.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - List of coupons.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [Route("relationships")]
        public async Task<ActionResult> FetchRelationshipsAsync([FromBody] Relationship.FilterModel model)
        {
            try
            {
                var records = await this.service.FetchRelationshipAsync(model);
                var menuButtons = await this.service.FetchMenuButtonsAsync(model);
                var groupList = records.GroupBy(x => x.MainPage).ToList();

                var overAllList = groupList.Select(list =>
                    new Relationship.OverallViewModel
                    {
                        ModuleName = list.Key,
                        Icon = list.First().Icon,
                        SubModules = list.OrderBy(x => x.Priority).ToList()
                    }).ToList();

                var data = new Relationship.MultiViewModel
                {
                    Access = await this.service.GetMenuAccessAsync(model),
                    Relationships = overAllList.OrderBy(x => x.ModuleName).ToList(),
                    MenuButtons = menuButtons.ToList()
                };

                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Success,
                    Data = data
                });
            }
            catch (Exception e)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = e.Message
                });
            }
        }

        /// <summary>
        /// Fetches the roles asynchronous.
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("roles")]
        public async Task<ActionResult> FetchRolesAsync()
        {
            var records = await this.service.FetchRolesAsync();
            return Ok(new GenericResponse
            {
                Status = GenericStatus.Success,
                Data = records
            });
        }

        /// <summary>
        /// Fetches the asynchronous.
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch")]
        public async Task<ActionResult> FetchAsync()
        {
            var records = await this.service.FetchAsync();
            return Ok(new GenericResponse
            {
                Status = GenericStatus.Success,
                Data = records
            });
        }

        /// <summary>
        /// Fetches the asynchronous.
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("free-fetch")]
        public async Task<ActionResult> FreeFetchAsync()
        {
            var records = await this.service.FreeFetchAsync();
            return Ok(new GenericResponse
            {
                Status = GenericStatus.Success,
                Data = records
            });
        }


        /// <summary>
        /// The add coupon.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Coupon added successfully.
        /// - 409 - Coupon already exist.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [Route("insert")]
        public async Task<ActionResult> AddAsync([FromBody] List<InsertModel> model)
        {
            try
            {
                var response = await this.service.AddAsync(model);
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Success,
                    Data = response
                });
            }
            catch (Exception e)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = e.Message
                });
            }
        }

        /// <summary>
        /// The add coupon.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Coupon added successfully.
        /// - 409 - Coupon already exist.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [Route("insert-only")]
        public async Task<ActionResult> AddOnlyAsync([FromBody] InsertModel model)
        {
            try
            {
                var response = await this.service.AddOnlyAsync(model);
                return Ok(new GenericResponse
                {
                    Status = response > 0 ? GenericStatus.Success : GenericStatus.Error,
                    Data = response
                });
            }
            catch (Exception e)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = e.Message
                });
            }
        }

        /// <summary>
        /// The add coupon.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Coupon added successfully.
        /// - 409 - Coupon already exist.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [Route("remove-only")]
        public async Task<ActionResult> RemoveOnlyAsync([FromBody] InsertModel model)
        {
            try
            {
                var response = await this.service.RemoveOnlyAsync(model);
                return Ok(new GenericResponse
                {
                    Status = response > 0 ? GenericStatus.Success : GenericStatus.Error,
                    Data = response
                });
            }
            catch (Exception e)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = e.Message
                });
            }
        }


        /// <summary>
        /// The add coupon.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Coupon added successfully.
        /// - 409 - Coupon already exist.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [Route("update")]
        public async Task<ActionResult> UpdateAsync([FromBody] UpdateModel model)
        {
            try
            {

                var response = await this.service.UpdateAsync(model);
                return Ok(new GenericResponse
                {
                    Status = response > 0 ? GenericStatus.Success : GenericStatus.Warning,
                    Data = response
                });
            }
            catch (Exception e)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = e.Message
                });
            }
        }

        /// <summary>
        /// The add coupon.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Coupon added successfully.
        /// - 409 - Coupon already exist.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [Route("add-button")]
        public async Task<ActionResult> AddButtonAsync([FromBody] Button.InsertModel model)
        {
            try
            {
                var response = await this.service.AddButtonAsync(model);
                return Ok(new GenericResponse
                {
                    Status = response > 0 ? GenericStatus.Success : GenericStatus.Warning,
                    Data = response
                });
            }
            catch (Exception e)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = e.Message
                });
            }
        }

        /// <summary>
        /// The add coupon.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Coupon added successfully.
        /// - 409 - Coupon already exist.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [Route("update-relationships")]
        public async Task<ActionResult> UpdateRelationshipsAsync([FromBody] Relationship.UpdateModel model, [FromHeader] LocationHeader header)
        {
            try
            {
                var response = await this.service.UpdateRelationshipsAsync(model);
                var role = await this.service.FindNameByRoleId(model.RoleId);
                try
                {
                    var auditLogModel = new AuditLogModel
                    {
                        AccountId = model.ModifiedBy,
                        LogTypeId = (int)LogTypes.Access,
                        LogFrom = (short)model.RoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = $@"{model.ModifiedByName} has <b>Updated</b> access for the <b> {role} </b> role Successfully on {DateTime.UtcNow.AddMinutes(330).ToString("MM/dd/yyyy hh:mm tt")} ",
                        LocationId = Convert.ToInt32(header.LocationId)
                    };
                    await this.auditLogServices.LogAsync(auditLogModel);
                }
                catch (Exception e)
                {
                    //audit
                }

                return Ok(new GenericResponse
                {
                    Status = response > 0 ? GenericStatus.Success : GenericStatus.Warning,
                    Data = response
                });
            }
            catch (Exception e)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = e.Message
                });
            }
        }


    }
}