namespace Hims.Api.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Domain.Services;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;

    using Newtonsoft.Json;

    using Shared.DataFilters;
    using Shared.EntityModels;
    using Shared.Library.Enums;
    using Utilities;
    using Hims.Api.Models.Chat;
    using Hims.Domain.Helpers;
    using Hims.Api.Models;

    /// <inheritdoc />
    [Authorize]
    [Route("api/chat")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class ChatController : BaseController
    {
        /// <summary>
        /// The Chat services.
        /// </summary>
        private readonly IChatService chatServices;

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

        /// <summary> The push notification helper.</summary>
        private readonly IPushNotificationHelper pushNotificationHelper;

        /// <summary>
        /// The account session services.
        /// </summary>
        private readonly IAccountSessionService accountSessionServices;

        /// <summary>
        /// The account services.
        /// </summary>
        private readonly IAccountService accountServices;

        /// <inheritdoc />
        public ChatController(IChatService chatServices, IAuditLogService auditLogServices, IAccountSessionService accountSessionServices, IAccountService accountServices, IPushNotificationHelper pushNotificationHelper)
        {
            this.chatServices = chatServices;
            this.auditLogServices = auditLogServices;
            this.accountSessionServices = accountSessionServices;
            this.accountServices = accountServices;
            this.pushNotificationHelper = pushNotificationHelper;
        }

        /// <summary>
        /// The fetch Chat.
        /// </summary>
        /// <param name="model">
        /// The Chat model.
        /// </param>
        /// <returns>
        /// The list of Chat.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - List of Chat.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [Route("fetch")]
        [ProducesResponseType(typeof(List<ChatModel>), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FetchAsync([FromBody]ChatFetchRequestModel model)
        {
            model = (ChatFetchRequestModel)EmptyFilter.Handler(model);
            var chat = await this.chatServices.FetchAsync(
                           model.SenderId,
                           model.SenderType,
                           model.ReceiverId,
                           model.ReceiverType,
                           model.CreatedDate);
            return chat == null ? this.ServerError() : this.Success(chat);
        }

        /// <summary> The find async.</summary>
        /// <param name="model"> The model.</param>
        /// <returns>The <see cref="Task"/>.</returns>
        [AllowAnonymous]
        [HttpPost]
        [Route("find")]
        [ProducesResponseType(typeof(ChatModel), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FindAsync([FromBody] ChatRequestModel model)
        {
            model = (ChatRequestModel)EmptyFilter.Handler(model);

            var response = await this.chatServices.FindAsync(model.ChatId);

            return response == null ? this.BadRequest("Sorry! We don't have a chat in the system") : this.Success(response);
        }

        /// <summary>
        /// The add Chat.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Chat added successfully.
        /// - 409 - Chat already exist.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [Route("save")]
        [ProducesResponseType(typeof(ChatModel), 200)]
        [ProducesResponseType(409)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> AddAsync([FromBody]ChatModel model, [FromHeader] LocationHeader header)
        {
            model = (ChatModel)EmptyFilter.Handler(model);
            model.LocationId = Convert.ToInt32(header.LocationId);
            var response = await this.chatServices.SaveAsync(model);

            if (response == 0)
            {
                return this.ServerError();
            }

            var accountSession = await this.accountSessionServices.FetchAsync(model.ReceiverId);

            var sessions = accountSession as AccountSessionModel[] ?? accountSession.ToArray();
            if (sessions.Any())
            {
                var accountSessionModels = accountSession as AccountSessionModel[] ?? sessions.ToArray();

                var deviceTokenAndroid = accountSessionModels.Where(d => d.DeviceType == 2).Select(s => s.DeviceToken)
                    .ToList();
                var deviceTokensIOS = accountSessionModels.Where(d => d.DeviceType == 3).Select(s => s.DeviceToken).ToList();
                var namePic = await this.accountServices.FindAsync(model.SenderId);
                var pushNotificationChatModel = new PushNotificationChatModel
                {
                    SenderType = model.SenderType,
                    SenderId = model.SenderId,
                    ReceiverId = model.ReceiverId,
                    ReceiverType = model.ReceiverType,
                    Message = model.Message,
                    Name = namePic.FullName,
                    Thumbnail = namePic.ThumbnailUrl
                };

                await this.pushNotificationHelper.SendChatNotificationsAsync("Hims", "Chat", JsonConvert.SerializeObject(pushNotificationChatModel), deviceTokenAndroid, deviceTokensIOS);
            }

            var auditLogModel = new AuditLogModel
            {
                AccountId = model.SenderId,
                LogTypeId = (int)LogTypes.Chat,
                LogFrom = (int)AccountType.Administrator,
                LogDate = DateTime.UtcNow,
                LogDescription = $"{model.SenderType}Id- {model.SenderId} sent a chat '{model.Message.ToUpper()}' to {model.ReceiverType}Id- {model.ReceiverId}.",
                LocationId=model.LocationId
            };
            await this.auditLogServices.LogAsync(auditLogModel);

            model.ChatId = response;
            return this.Success(model);
        }

        /// <summary>
        /// The delete Chat.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Chat deleted successfully.
        /// - 409 - Chat can not be deleted.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpDelete]
        [Route("delete")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(409)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> DeleteAsync([FromBody]ChatRequestModel model,[FromHeader]LocationHeader header)
        {
            model = (ChatRequestModel)EmptyFilter.Handler(model);
            
            var response = await this.chatServices.DeleteAsync(model.ChatId);
            if (response == 0)
            {
                return this.ServerError();
            }

            var auditLogModel = new AuditLogModel
            {
                AccountId = model.AccountId,
                LogTypeId = (int)LogTypes.Chat,
                LogFrom = (int)AccountType.Administrator,
                LogDate = DateTime.UtcNow,
                LogDescription = $"Chat Id-{model.ChatId}  has been deleted.",
                LocationId = Convert.ToInt32(header.LocationId)
            };
            await this.auditLogServices.LogAsync(auditLogModel);

            return this.Success("Chat has been deleted successfully.");
        }
    }
}