using System.Collections.Generic;
using Newtonsoft.Json;
using Hims.Shared.UserModels;

namespace Hims.Api.Controllers
{
    using System;
    using System.Threading.Tasks;
    using Domain.Helpers;
    using Domain.Services;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using RestSharp;
    using Shared.DataFilters;
    using Shared.EntityModels;
    using Utilities;

    /// <summary>
    /// The Push Notification Controller
    /// </summary>
    [AllowAnonymous]
    [Route("api/pushNotification")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class PushNotificationController : BaseController
    {
        /// <summary>
        /// the push notification helper
        /// </summary>
        private readonly IPushNotificationHelper pushNotificationHelper;

        /// <summary>
        /// the push telemedicine service
        /// </summary>
        private readonly IWebTelemedicineService telemedicineService;

        /// <inheritdoc />
        public PushNotificationController(IPushNotificationHelper pushNotificationHelper, IWebTelemedicineService telemedicineService)
        {
            this.telemedicineService = telemedicineService;
            this.pushNotificationHelper = pushNotificationHelper;
        }

        /// <summary>
        /// The push notification.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("video-call-notifications")]
        [ProducesResponseType(typeof(void), 200)]
        [ProducesResponseType(409)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> SendAsync([FromBody] VideoCallPushNotificationModel model)
        {
            model = (VideoCallPushNotificationModel)EmptyFilter.Handler(model);
            await this.pushNotificationHelper.SendVideoCallNotificationsAsync("Hims", "Incoming call", model.Message, model.DeviceToken, model.DoctorName, model.DoctorEmail, model.DeviceId);
            return this.Success("Sent push notification successfully.");
        }

        /// <summary>
        /// The push notification.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("test")]
        [ProducesResponseType(typeof(void), 200)]
        [ProducesResponseType(409)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> TestAsync([FromBody] TestNotificationModel model)
        {
            model = (TestNotificationModel)EmptyFilter.Handler(model);

            var response = await pushNotificationHelper.IntimateAsync(
                        "Hims",
                        "Test Message",
                        "Test Type",
                        new List<string> { model.AndroidToken },
                        new List<string> { model.IosToken },
                        string.Empty);

            return this.Success(JsonConvert.SerializeObject(response));
        }

        /// <summary>
        /// The push notification.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("telemedicine-notification")]
        [ProducesResponseType(typeof(void), 200)]
        [ProducesResponseType(409)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> TelemedicineAsync([FromBody] VideoCallPushNotificationModel model)
        {
            model = (VideoCallPushNotificationModel)EmptyFilter.Handler(model);
            IRestResponse restResponse = null;
            var telemedicineId = model.TelemedicineId;
            var sendNotification = model.DeviceTokens.Count > 0;
            var userRejectedCall = true;
            try
            {
                if (model.AppointmentId != 0 && model.TelemedicineId == 0)
                {
                    telemedicineId = await this.telemedicineService.CreateAsync(model.AppointmentId);
                }

                if (model.TelemedicineId != 0)
                {
                    var status = await this.telemedicineService.GetStatusAsync(model.TelemedicineId);
                    if (status == 2)
                    {
                        userRejectedCall = false;
                    }
                    else
                    {
                        await this.telemedicineService.UpdateCountAsync(model.TelemedicineId);
                    }
                }
            }
            catch
            {
                // ignore
            }

            if (sendNotification)
            {
                restResponse = await this.pushNotificationHelper.TelemedicineCallNotification("Jitsi", model.Message, model.DeviceTokens, model.DoctorName, telemedicineId);
            }

            var content = sendNotification ? (object)restResponse.Content : new { };
            return this.Success(
                new
                {
                    data = telemedicineId,
                    status = userRejectedCall,
                    content,
                    message = "Sent push notification successfully."
                });
        }

        /// <summary>
        /// The push notification.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("notification-intimate")]
        [ProducesResponseType(typeof(void), 200)]
        [ProducesResponseType(409)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> NotificationIntimateAsync([FromBody] NotificationIntimateModel model)
        {
            try
            {
                var restResponse = await this.pushNotificationHelper.TelemedicineCallNotification(model);
                var content = (object)restResponse.Content;
                return this.Success(
                    new
                    {
                        content,
                        message = "Sent push notification successfully."
                    });
            }
            catch (Exception exception)
            {
                return this.Success(
                    new
                    {
                        content = exception.Message,
                        message = "Push notification failed."
                    });
            }
        }

        /// <summary>
        /// The push notification.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("sinch-telemedicine-notification")]
        [ProducesResponseType(typeof(void), 200)]
        [ProducesResponseType(409)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> SinchTelemedicineAsync([FromBody] VideoCallPushNotificationModel model)
        {
            model = (VideoCallPushNotificationModel)EmptyFilter.Handler(model);
            var restResponse = await this.pushNotificationHelper.TelemedicineCallNotification("Sinch", model.Message, model.DeviceTokens, model.DoctorName, 0);

            var content = (object)restResponse.Content;
            return this.Success(
                new
                {
                    content,
                    message = "Sent push notification successfully."
                });
        }

        /// <summary>
        /// The push notification.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("video-call-notifications-all-devices")]
        [ProducesResponseType(typeof(void), 200)]
        [ProducesResponseType(409)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> SendAllAsync([FromBody] VideoCallPushNotificationToAllDevicesModel model)
        {
            model = (VideoCallPushNotificationToAllDevicesModel)EmptyFilter.Handler(model);
            await this.pushNotificationHelper.SendVideoCallNotificationsToAllDevicesAsync("Hims", "Incoming call", model.Message, model.DeviceToken, model.DoctorName, model.DoctorEmail, model.DeviceId);
            return this.Success("Sent push notification successfully.");
        }
    }
}
