using Femto.Api.Auth;
using Femto.Api.Sessions;
using Femto.Common;
using Femto.Modules.Auth.Application;
using Femto.Modules.Auth.Application.Dto;
using Femto.Modules.Auth.Application.Interface.CreateSignupCode;
using Femto.Modules.Auth.Application.Interface.GetSignupCodesQuery;
using Femto.Modules.Auth.Application.Interface.Login;
using Femto.Modules.Auth.Application.Interface.RefreshUserSession;
using Femto.Modules.Auth.Application.Interface.Register;
using Femto.Modules.Auth.Contracts;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;

namespace Femto.Api.Controllers.Auth;

[ApiController]
[Route("auth")]
public class AuthController(
    IAuthModule authModule,
    IOptions<CookieSettings> cookieSettings,
    ICurrentUserContext currentUserContext,
    ILogger<AuthController> logger
) : ControllerBase
{
    [HttpPost("login")]
    public async Task<ActionResult<LoginResponse>> Login([FromBody] LoginRequest request)
    {
        var result = await authModule.Command(new LoginCommand(request.Username, request.Password));

        HttpContext.SetSession(result.Session, result.User, logger);

        return new LoginResponse(
            result.User.Id,
            result.User.Username,
            result.User.Roles.Any(r => r == Role.SuperUser)
        );
    }

    [HttpPost("register")]
    public async Task<ActionResult<RegisterResponse>> Register([FromBody] RegisterRequest request)
    {
        var result = await authModule.Command(
            new RegisterCommand(request.Username, request.Password, request.SignupCode)
        );

        HttpContext.SetSession(result.Session, result.User, logger);

        return new RegisterResponse(
            result.User.Id,
            result.User.Username,
            result.User.Roles.Any(r => r == Role.SuperUser)
        );
    }

    [HttpDelete("session")]
    public async Task<ActionResult> DeleteSession()
    {
        HttpContext.DeleteSession();
        return Ok(new { });
    }

    [HttpGet("user/{userId}")]
    [Authorize]
    public async Task<ActionResult<RefreshUserResult>> RefreshUser(
        Guid userId,
        CancellationToken cancellationToken
    )
    {
        var currentUser = currentUserContext.CurrentUser!;

        try
        {
            var result = await authModule.Command(
                new RefreshUserSessionCommand(userId, currentUser),
                cancellationToken
            );

            return new RefreshUserResult(
                result.User.Id,
                result.User.Username,
                result.User.Roles.Any(r => r == Role.SuperUser)
            );
        }
        catch (Exception)
        {
            HttpContext.DeleteSession();
            return this.Forbid();
        }
    }

    [HttpPost("signup-codes")]
    [Authorize(Roles = "SuperUser")]
    public async Task<ActionResult> CreateSignupCode(
        [FromBody] CreateSignupCodeRequest request,
        CancellationToken cancellationToken
    )
    {
        await authModule.Command(
            new CreateSignupCodeCommand(request.Code, request.Email, request.Name),
            cancellationToken
        );

        return Ok(new { });
    }

    [HttpGet("signup-codes")]
    [Authorize(Roles = "SuperUser")]
    public async Task<ActionResult<ListSignupCodesResult>> ListSignupCodes(
        CancellationToken cancellationToken
    )
    {
        var codes = await authModule.Query(new GetSignupCodesQuery(), cancellationToken);

        return new ListSignupCodesResult(
            codes.Select(c => new SignupCodeDto(
                c.Code,
                c.Email,
                c.Name,
                c.RedeemedByUserId,
                c.RedeemedByUsername,
                c.ExpiresOn
            ))
        );
    }
}
