// Copyright © Selmo Technology GmbH. All Rights Reserved

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SelmoStudio.Hmi.Plugin.Model.RestApi;
using SelmoStudio.Hmi.Plugin.Model.User;
using SelmoStudio.Hmi.Server.Db.Authentication;
using SelmoStudio.Hmi.Server.Db.Authentication.Service;
using System.Security.Claims;
using System.Text.Json;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace SelmoStudio.Hmi.Server.Api
{
    [Route("api/[controller]")]
    [ApiController]
    public class UserManagementController : ControllerBase
    {
        private readonly ISelmoAuthenticationService _selmoAuthenticationService;

        public UserManagementController(ISelmoAuthenticationService selmoAuthenticationService)
        {
            _selmoAuthenticationService = selmoAuthenticationService;
        }

        [AllowAnonymous]
        [HttpGet("find/{username}")]
        [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))]
        [ProducesResponseType(StatusCodes.Status500InternalServerError)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        public async Task<string> Find(string username)
        {
            var response = await _selmoAuthenticationService.Find(username);

            if (response.HasNoValue)
            {
                //return BadRequest($"Cannot find user {username}.");
            }
            var mapped = Map(response.Value);
            var serialized = JsonSerializer.Serialize(mapped);
            return serialized;
        }

        [AllowAnonymous]
        [HttpGet("exists/{username}")]
        [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))]
        [ProducesResponseType(StatusCodes.Status500InternalServerError)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        public async Task<bool> Exists(string username)
        {
            var response = await _selmoAuthenticationService.Exists(username);

            return response;
        }

        [AllowAnonymous]
        [HttpGet("getByName/{username}")]
        [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))]
        [ProducesResponseType(StatusCodes.Status500InternalServerError)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        public async Task<string> GetByName(string username)
        {
            var response = await _selmoAuthenticationService.GetByName(username);

            var mapped = Map(response);
            var serialized = JsonSerializer.Serialize(mapped);
            return serialized;
        }

        [AllowAnonymous]
        [HttpGet("getAll")]
        [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))]
        [ProducesResponseType(StatusCodes.Status500InternalServerError)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        public async Task<string> GetAll()
        {
            var appUsers = await _selmoAuthenticationService.GetAll();

            List<UserSettings> userSettings = new();
            foreach (var appUser in appUsers)
            {
                userSettings.Add(await Map(appUser));
            }

            return JsonSerializer.Serialize(userSettings);
        }

        private async Task<List<UserSettings>> Map(List<ApplicationUser> appUsers)
        {
            List<UserSettings> userSettings = new();
            foreach (var appUser in appUsers)
            {
                userSettings.Add(await Map(appUser));
            }
            return userSettings;
        }

        private async Task<UserSettings> Map(ApplicationUser appUser)
        {
            UserSettings userSetting = new();
            userSetting.Username = appUser.UserName;
            userSetting.Password = string.Empty; // TODO No password info available
            userSetting.Email = appUser.Email;
            userSetting.Permissions = new();

            var claims = await _selmoAuthenticationService.GetClaims(appUser);

            foreach (var claim in claims)
            {
                userSetting.Permissions.Add(GetUserPermission(claim));
            }

            return userSetting;
        }

        private static UserPermission GetUserPermission(Claim claim)
        {
            // TODO Fix this

            if (claim.Value == WellKnownPermissionClaims.SystemManaging)
            {
                return WellKnownPermissions.SystemManage;
            }

            if (claim.Value == WellKnownPermissionClaims.ReadSettings)
            {
                return WellKnownPermissions.ReadSettings;
            }

            if (claim.Value == WellKnownPermissionClaims.WriteSettings)
            {
                return WellKnownPermissions.WriteSettings;
            }

            if (claim.Value == WellKnownPermissionClaims.ReadHistoryValue)
            {
                return WellKnownPermissions.ReadHistoryValue;
            }

            if (claim.Value == WellKnownPermissionClaims.WriteHistoryValue)
            {
                return WellKnownPermissions.WriteHistoryValue;
            }

            if (claim.Value == WellKnownPermissionClaims.ReadProcessValue)
            {
                return WellKnownPermissions.ReadProcessValue;
            }

            if (claim.Value == WellKnownPermissionClaims.WriteProcessValue)
            {
                return WellKnownPermissions.WriteProcessValue;
            }

            throw new NotSupportedException($"Claim {claim.Value} is not supported.");
        }

        [AllowAnonymous]
        [HttpDelete("delete/{username}")]
        [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))]
        [ProducesResponseType(StatusCodes.Status500InternalServerError)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        public async Task<IActionResult> Delete(string username)
        {
            var response = await _selmoAuthenticationService.Delete(username);

            if (response.HasNoValue)
            {
                return BadRequest(response);
            }

            return Ok("");
        }

        [AllowAnonymous]
        [HttpPost("login")]
        [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))]
        [ProducesResponseType(StatusCodes.Status500InternalServerError)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        public async Task<IActionResult> Login([FromBody] LoginRequest request)
        {
            var response = await _selmoAuthenticationService.Login(request, HttpContext);

            return Ok(response);
        }

        [AllowAnonymous]
        [HttpPost("register")]
        [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))]
        [ProducesResponseType(StatusCodes.Status500InternalServerError)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        public async Task<IActionResult> Register([FromBody] RegisterRequest request)
        {
            var response = await _selmoAuthenticationService.Register(request, HttpContext);

            return Ok(response);
        }

        [AllowAnonymous]
        [HttpPost("update")]
        [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))]
        [ProducesResponseType(StatusCodes.Status500InternalServerError)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        public async Task<IActionResult> Update([FromBody] UpdateRequest request)
        {
            var response = await _selmoAuthenticationService.Update(request, HttpContext);

            return Ok(response);
        }

        [HttpPost]
        [HttpPost("logout")]
        [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))]
        [ProducesResponseType(StatusCodes.Status500InternalServerError)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        public async Task<IActionResult> Logout([FromBody] LogoutRequest logoutRequest)
        {
            var response = await _selmoAuthenticationService.Logout(logoutRequest.Username, HttpContext);

            return Ok(response);
        }
    }
}