using IdentityServer4;
using IdentityServer4.Services;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Infra.EFCore;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
using System;
using System.Threading.Tasks;

namespace IRaCIS.Core.IdentityServer4.Account
{

    [ApiController]
    [AllowAnonymous]
    public class AuthenticateController : Controller
    {
        private readonly IIdentityServerInteractionService _interaction;
        private readonly IWebHostEnvironment _environment;
        private readonly IRepository<User> _userRepository;

        public AuthenticateController(
            IIdentityServerInteractionService interaction,
            IWebHostEnvironment environment, IRepository<User> userRepository)
        {
            _interaction = interaction;
            _environment = environment;
            _userRepository = userRepository;
        }

        public class LoginRequest
        {
            public string UserName { get; set; }
            public string Password { get; set; }
            public string ReturnUrl { get; set; }

            public bool RememberLogin { get; set; }
        }
        [Route("user/login")]
        [HttpPost]
        public async Task<IActionResult> Login([FromBody]LoginRequest request)
        {

            var a = "/connect/authorize/callback?client_id=spa&redirect_uri=http%3A%2F%2Flocalhost%3A8081%2Fcallback.html&response_type=code&scope=openid%20%20profile&state=05d78e28fabf4af889f408123cfd6109&code_challenge=DmFSo8DgWoL7J9rT5BLPHwIWeAKJWKGR_ZYmxCaWmEw&code_challenge_method=S256&display=popup";

            var context = await _interaction.GetAuthorizationContextAsync(request.ReturnUrl);
            var user = await _userRepository
                   .FirstOrDefaultAsync(usr => usr.Password == request.Password && usr.UserName == request.UserName);

            if (user != null && context != null)
            {

                AuthenticationProperties props = null;
                if (request.RememberLogin)
                {
                    props = new AuthenticationProperties
                    {
                        IsPersistent = true,
                        ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromDays(1))
                    };
                };

                var identityServerUser = new IdentityServerUser(user.Id.ToString())
                {
                    DisplayName = request.UserName
                };

                await HttpContext.SignInAsync(identityServerUser, props);

                return new JsonResult(new { RedirectUrl = request.ReturnUrl, IsOk = true });
            }

            return Unauthorized();
        }

        [HttpGet]
        [Route("user/logout")]
        public async Task<IActionResult> Logout(string logoutId)
        {
            var context = await _interaction.GetLogoutContextAsync(logoutId);
            bool showSignoutPrompt = true;

            if (context?.ShowSignoutPrompt == false)
            {
                // it's safe to automatically sign-out
                showSignoutPrompt = false;
            }

            if (User?.Identity.IsAuthenticated == true)
            {
                // delete local authentication cookie
                await HttpContext.SignOutAsync();
            }

            // no external signout supported for now (see \Quickstart\Account\AccountController.cs TriggerExternalSignout)
            return Ok(new
            {
                showSignoutPrompt,
                ClientName = string.IsNullOrEmpty(context?.ClientName) ? context?.ClientId : context?.ClientName,
                context?.PostLogoutRedirectUri,
                context?.SignOutIFrameUrl,
                logoutId
            });
        }

        [HttpGet]
        [Route("Error")]
        public async Task<IActionResult> Error(string errorId)
        {
            // retrieve error details from identityserver
            var message = await _interaction.GetErrorContextAsync(errorId);

            if (message != null)
            {
                if (!_environment.IsDevelopment())
                {
                    // only show in development
                    message.ErrorDescription = null;
                }
            }

            return Ok(message);
        }
    }
}