using Microsoft.AspNetCore.Mvc;
using bitforum.DTOs.Request;
using bitforum.DTOs.Response;
using bitforum.Constants;
using bitforum.Helpers;
using bitforum.Services;
using bitforum.Repository;

namespace bitforum.Controllers.API.Auth
{
    [ApiController]
    [Route("api/auth")]
    public class PasswordController : ControllerBase
    {
        private readonly ILogger<PasswordController> _logger;
        private readonly DefaultDbContext _db;
        private readonly IConfigService _configService;
        private readonly IMailService _mailService;
        private readonly IMemberRepository _memberRepository;
        private ResultDto _result = new ResultDto();

        public PasswordController(ILogger<PasswordController> logger, DefaultDbContext db, IConfigService configService, IMailService mailService, IEmailVerifyNumberRepository emailVerifyNumberRepository, IMemberRepository memberRepository)
        {
            _logger = logger;
            _db = db;
            _configService = configService;
            _mailService = mailService;
            _memberRepository = memberRepository;
        }

        // 비밀번호 재설정 요청
        [HttpGet("forgot-password/{email}")]
        public async Task<ActionResult<ResultDto>> ForgotPassword([FromRoute] string email)
        {
            try
            {
                if (string.IsNullOrEmpty(email))
                {
                    throw new Exception("잘못된 접근입니다.");
                }

                // 이메일 거부 목록 확인
                if (_configService.IsDeniedEmail(email))
                {
                    throw new Exception($"`{email}`은 조회할 수 없습니다.");
                }

                // 회원 확인
                var member = await _memberRepository.FindMemberByEmail(email);
                if (member is null)
                {
                    throw new Exception("회원 정보를 찾을 수 없습니다.");
                }

                // 차단 회원은 거부
                if (member.IsDenied)
                {
                    throw new Exception("권한이 없습니다.");
                }

                await _mailService.SendForgotPasswordEmailAsync(member);

                _result.Message = "이메일 인증 확인 후 비밀번호를 변경할 수 있습니다.";
            }
            catch (Exception e)
            {
                _logger.LogError(e, e.Message);
                _result.Ok = false;
                _result.Status = StatusCodes.Status400BadRequest;
                _result.Message = e.Message;
            }

            return _result;
        }

        // 비밀번호 변경 처리
        [HttpPost("reset-password")]
        public async Task<ActionResult<ResultDto>> ResetPassword([FromBody] ResetPasswordDto request)
        {
            try
            {
                var cookieName = $"isVerified-{VerificationType.ForgotPassword}";
                if (!Request.Cookies.ContainsKey(cookieName) || Request.Cookies[cookieName] != "true")
                {
                    throw new Exception("사전 인증을 먼저 수행하세요.");
                }

                // 유효성 검사
                if (!ModelState.IsValid)
                {
                    _result.Errors = ModelState.GetErrors();
                    throw new Exception("유효성 검사에 실패하였습니다.");
                }

                // 회원 확인
                var member = await _memberRepository.FindMemberByEmail(request.Email);
                if (member is null)
                {
                    throw new Exception("회원 정보를 찾을 수 없습니다.");
                }

                var newPassword = BCrypt.Net.BCrypt.HashPassword(request.Password);
                if (member.Password == newPassword)
                {
                    throw new Exception("기존 비밀번호와 동일합니다.");
                }

                var isValid = _configService.IsPasswordPolicyValid(request.Password);
                if (!isValid)
                {
                    string message = "";
                    int minLengthConfig = Config.Register.PasswordMinLength ?? 6;
                    int uppercaseLengthConfig = Config.Register.PasswordUppercaseLength ?? 0;
                    int numbersLengthConfig = Config.Register.PasswordNumbersLength ?? 0;
                    int specialCharsLengthConfig = Config.Register.PasswordSpecialcharsLength ?? 0;

                    // 위에 데이터로 안내 문구 만들어줘
                    if (minLengthConfig > 0)
                    {
                        message += $"최소 {minLengthConfig}자 이상, ";
                    }
                    if (uppercaseLengthConfig > 0)
                    {
                        message += $"대문자 {uppercaseLengthConfig}자 이상, ";
                    }
                    if (numbersLengthConfig > 0)
                    {
                        message += $"숫자 {numbersLengthConfig}자 이상, ";
                    }
                    if (specialCharsLengthConfig > 0)
                    {
                        message += $"특수문자 {specialCharsLengthConfig}자 이상, ";
                    }

                    message = message.TrimEnd(',', ' ');

                    throw new Exception($"입력하신 비밀번호는 사용하실 수 없습니다. 다음 조건을 충족해주세요.\n\n{message}");
                }

                member.Password = newPassword;
                member.PasswordUpdatedAt = DateTime.UtcNow;

                await _db.SaveChangesAsync();
                await _mailService.SendChangedPasswordEmailAsync(member);

                // 쿠키 삭제
                Response.Cookies.Delete(cookieName);

                _result.Message = "비밀번호가 변경되었습니다.";
            }
            catch (Exception e)
            {
                _logger.LogError(e, e.Message);
                _result.Ok = false;
                _result.Status = StatusCodes.Status400BadRequest;
                _result.Message = e.Message;
            }
            return _result;
        }
    }
}
