namespace Hims.Admin.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Claims;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Newtonsoft.Json;
    using Shared.Library;
    using Utilities;

    /// <inheritdoc />
    [Route("api/identity")]
    [Consumes("application/json")]
    [Produces("application/json")]
    [AllowAnonymous]
    public class IdentityController : BaseController
    {
        /// <summary>
        /// The sign in user.
        /// </summary>
        /// <param name="userIdentity">
        /// The user identity model.
        /// </param>
        /// <returns>
        /// The http response. <see cref="ActionResult"/>.
        /// </returns>
        [ProducesResponseType(200)]
        [ProducesResponseType(500)]
        [HttpPost]
        [Route("sign-in")]
        public async Task<ActionResult> SignInAsync([FromBody] UserAccount userIdentity)
        {
            try
            {
                var claims = new List<Claim> { new Claim("UserAccount", JsonConvert.SerializeObject(userIdentity)) };
                var claimsIdentity = new ClaimsIdentity(claims, "login");
                var principal = new ClaimsPrincipal(claimsIdentity);
                await this.HttpContext.SignInAsync(principal);
                return this.Success();
            }
            catch (Exception exception)
            {
                return this.ServerError(exception);
            }
        }

        /// <summary>
        /// The get user identity.
        /// </summary>
        /// <returns>
        /// The http response. <see cref="ActionResult"/>.
        /// </returns>
        [ProducesResponseType(200)]
        [ProducesResponseType(500)]
        [HttpPost]
        [Route("get")]
        public ActionResult GetIdentity()
        {
            try
            {
                if (!this.User.Identity.IsAuthenticated)
                {
                    return this.Success();
                }

                var user = this.User;
                if (!(user.Identity is ClaimsIdentity identity))
                {
                    return this.Success();
                }

                var userAccount = identity.Claims.SingleOrDefault(x => x.Type == "UserAccount")?.Value ?? string.Empty;
                var userIdentity = JsonConvert.DeserializeObject<UserAccount>(userAccount);
                return this.Success(userIdentity);
            }
            catch (Exception exception)
            {
                return this.ServerError(exception);
            }
        }

        /// <summary>
        /// The get user identity status.
        /// </summary>
        /// <returns>
        /// The http response. <see cref="ActionResult"/>.
        /// </returns>
        [ProducesResponseType(200)]
        [ProducesResponseType(500)]
        [HttpPost]
        [Route("status")]
        public ActionResult GetStatus()
        {
            try
            {
                if (!this.User.Identity.IsAuthenticated)
                {
                    return this.Success(0);
                }

                var user = this.User;
                if (!(user.Identity is ClaimsIdentity identity))
                {
                    return this.Success(0);
                }

                var userAccount = identity.Claims.SingleOrDefault(x => x.Type == "UserAccount")?.Value ?? string.Empty;
                var userIdentity = JsonConvert.DeserializeObject<UserAccount>(userAccount);
                return this.Success(userIdentity.RoleId);
            }
            catch (Exception exception)
            {
                return this.ServerError(exception);
            }
        }

        /// <summary>
        /// The update user identity.
        /// </summary>
        /// <param name="authToken">
        /// The auth token model.
        /// </param>
        /// <returns>
        /// The http response. <see cref="ActionResult"/>.
        /// </returns>
        [ProducesResponseType(200)]
        [ProducesResponseType(500)]
        [HttpPost]
        [Route("update")]
        public async Task<ActionResult> UpdateIdentityAsync([FromBody] AuthToken authToken)
        {
            try
            {
                var user = this.User;
                if (!(user.Identity is ClaimsIdentity identity))
                {
                    return this.ServerError();
                }

                var userAccount = identity.Claims.SingleOrDefault(x => x.Type == "UserAccount")?.Value ?? string.Empty;
                var userIdentity = JsonConvert.DeserializeObject<UserAccount>(userAccount);
                userIdentity.Token = authToken.Token;
                userIdentity.ReferenceToken = authToken.ReferenceToken;
                userIdentity.Expires = authToken.Expires;
                userIdentity.AllowVideoCall = authToken.AllowVideoCall;

                var claim = identity.Claims.ToList().SingleOrDefault(x => x.Type == "UserAccount");
                identity.RemoveClaim(claim);
                identity.AddClaim(new Claim("UserAccount", JsonConvert.SerializeObject(userIdentity)));
                await this.HttpContext.SignInAsync(user);
                return this.Success();
            }
            catch (Exception exception)
            {
                return this.ServerError(exception);
            }
        }

        /// <summary>
        /// The sign out user.
        /// </summary>
        /// <returns>
        /// The http response. <see cref="ActionResult"/>.
        /// </returns>
        [ProducesResponseType(200)]
        [ProducesResponseType(500)]
        [HttpPost]
        [Route("sign-out")]
        public async Task<ActionResult> SignOutAsync()
        {
            try
            {
                await this.HttpContext.SignOutAsync();
                return this.Success();
            }
            catch (Exception exception)
            {
                return this.ServerError(exception);
            }
        }
    }
}