using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using bitforum.DTOs.Request;
using bitforum.DTOs.Response;
using bitforum.Helpers;
using bitforum.Services;
using bitforum.Constants;
using bitforum.Models.Log;
using System.Web;

namespace bitforum.Controllers.API
{
    [ApiController]
    [Route("api/[controller]")]
    public class AuthController : ControllerBase
    {
        private readonly ILogger<AuthController> _logger;
        private readonly DefaultDbContext _db;
        private readonly IJwtAuthService _jwtAuthService;
        private readonly IMailService _mailService;
        private ResultDto _result = new ResultDto();

        public AuthController(ILogger<AuthController> logger, DefaultDbContext db, IJwtAuthService jwtAuthService, IMailService mailService)
        {
            _logger = logger;
            _db = db;
            _jwtAuthService = jwtAuthService;
            _mailService = mailService;
        }

        // 인증번호 검증
        [HttpPost("verification")]
        public async Task<ActionResult<ResultDto>> Verification([FromBody] VerificationNumberDto request)
        {
            try
            {
                // 유효성 검사
                if (!ModelState.IsValid)
                {
                    _result.Errors = ModelState.GetErrors();
                    throw new Exception("인증 거부");
                }

                // 회원 확인
                var member = await _db.Member.FirstOrDefaultAsync(c => c.Email == request.Email);
                if (member is null)
                {
                    throw new Exception("인증 불가");
                }

                // 인증번호 확인
                var isValid = await _mailService.VerifyCodeAsync(request.Email, request.Code, request.Type);
                if (!isValid)
                {
                    throw new Exception("인증 실패");
                }

                var cookie = new CookieOptions
                {
                    HttpOnly = true,
                    Secure = true,
                    SameSite = SameSiteMode.None
                };

                switch (request.Type)
                {
                    case VerificationType.Registration:
                        cookie.Expires = DateTime.UtcNow.AddMinutes(5);
                        break;

                    case VerificationType.ForgotPassword:
                        cookie.Expires = DateTime.UtcNow.AddMinutes(10);
                        break;
                }

                Response.Cookies.Append($"isVerified-{request.Type}", "true", cookie);
                Console.WriteLine("Set-Cookie Header:", Response.Headers["Set-Cookie"]);

                _result.Message = "인증 성공";
            }
            catch (Exception e)
            {
                _logger.LogError(e, e.Message);
                _result.Ok = false;
                _result.Status = StatusCodes.Status400BadRequest;
                _result.Message = e.Message;
            }

            return _result;
        }

        // 인증번호 다시 보내기
        [HttpPost("resend-verify")]
        public async Task<ActionResult<ResultDto>> ResendVerify([FromBody] ResendVerifyNumberDto request)
        {
            try
            {
                // 유효성 검사
                if (!ModelState.IsValid)
                {
                    _result.Errors = ModelState.GetErrors();
                    throw new Exception("잘못된 접근입니다.");
                }

                // 회원 확인
                var member = await _db.Member.FirstOrDefaultAsync(c => c.Email == request.Email);
                if (member is null)
                {
                    throw new Exception("회원을 조회할 수 없습니다.");
                }

                switch (request.Type)
                {
                    // 회원가입 이메일 인증 메일 발송
                    case VerificationType.Registration:
                        await _mailService.SendRegisterEmailAsync(member);
                        break;

                    // 비밀번호 재설정 이메일 발송
                    case VerificationType.ForgotPassword:
                        await _mailService.SendForgotPasswordEmailAsync(member);
                        break;
                }
             
                _result.Message = "인증 재전송 완료";
            }
            catch (Exception e)
            {
                _logger.LogError(e, e.Message);
                _result.Ok = false;
                _result.Status = StatusCodes.Status400BadRequest;
                _result.Message = e.Message;
            }

            return _result;
        }

        [HttpGet("verify-token")]
        public ActionResult<ResultDto> VerifyAccessToken()
        {
            try
            {
                if (!Request.Cookies.TryGetValue("accessToken", out var accessToken))
                {
                    throw new Exception("잘못된 접근입니다.");
                }

                var isValid = _jwtAuthService.ValidateAccessToken(accessToken);
                if (!isValid)
                {
                    throw new Exception("`AccessToken`이 유효하지 않습니다.");
                }

                var member = _jwtAuthService.GetMemberFromAccessToken(accessToken);
                if (member is null)
                {
                    throw new Exception("회원 정보를 찾을 수 없습니다.");
                }

                _logger.LogInformation("AccessToken 유효!");
                _result.Message = "OK";
            }
            catch (Exception e)
            {
                _logger.LogError(e, e.Message);
                _result.Ok = false;
                _result.Status = StatusCodes.Status400BadRequest;
                _result.Message = e.Message;
            }

            return _result;
        }

        // 재로그인 토큰 재발급
        [HttpGet("refresh-token")]
        public async Task<ActionResult<ResultDto>> RefreshToken()
        {
            try
            {
                if (!Request.Cookies.TryGetValue("refreshToken", out var refreshToken))
                {
                    throw new Exception("잘못된 접근입니다.");
                }

                var isValid = await _jwtAuthService.ValidateRefreshToken(refreshToken);
                if (!isValid)
                {
                    throw new Exception("확인할 수 없는 요청입니다.");
                }

                var member = await _jwtAuthService.GetMemberFromRefreshToken(refreshToken);
                if (member is null)
                {
                    throw new Exception("회원 정보를 찾을 수  없습니다.");
                }

                // JWT 토큰 발급
                await _jwtAuthService.SetRefreshTokenAndCookieAsync(member);

                _logger.LogInformation("RefreshToken 유효!");
                _result.Message = "OK";
            }
            catch (Exception e)
            {
                _logger.LogError(e, e.Message);
                _result.Ok = false;
                _result.Status = StatusCodes.Status400BadRequest;
                _result.Message = e.Message;
            }

            return _result;
        }

        [HttpGet("verify-email/{token}")]
        public async Task<ActionResult<ResultDto>> VerifyEmail([FromRoute] string token)
        {
            try
            {
                if (string.IsNullOrEmpty(token))
                {
                    _result.Errors = ModelState.GetErrors();
                    throw new Exception("유효성 검사에 실패했습니다.");
                }

                token = HttpUtility.UrlDecode(token);

                // 인증주소 확인
                var tokenData = await _mailService.VerifyTokenAsync(token, VerificationType.ChangedEmail);
                if (tokenData is null)
                {
                    throw new Exception("인증 실패");
                }

                if (string.IsNullOrEmpty(tokenData?.AdditionalData?.Email))
                {
                    throw new Exception("최소 필수 정보가 누락되었습니다.");
                }

                // 회원 조회
                var member = await _db.Member.FirstOrDefaultAsync(c => c.Email == tokenData.AdditionalData.Email);
                if (member is null)
                {
                    throw new Exception("회원 정보를 찾을 수 없습니다.");
                }

                await _db.EmailChangeLog.AddAsync(new EmailChangeLog
                {
                    MemberID = member.ID,
                    BeforeEmail = member.Email,
                    AfterEmail = tokenData.Email,
                    CreatedAt = DateTime.UtcNow
                });

                member.Email = tokenData.Email;
                member.LastEmailChangedAt = DateTime.UtcNow;

                await _db.SaveChangesAsync();

                await _mailService.SendChangedEmailAsync(member); // 이메일 변경 완료 메일 발송

                _result.Message = "이메일이 변경되었습니다.";
            }
            catch (Exception e)
            {
                _logger.LogError(e, e.Message);
                _result.Ok = false;
                _result.Status = StatusCodes.Status400BadRequest;
                _result.Message = e.Message;
            }

            return _result;
        }
    }
}
