using Domain.Entities.Members.ValueObject;
using SharedKernel.Extensions;
using SharedKernel.Storage;
using SharedKernel.Attributes;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace Admin.Pages.Member.List;

public class WriteModel(IMediator mediator, IFileStorage fileStorage) : PageModel
{
    private static readonly string[] AllowedFileExtensions = [".jpg", ".jpeg", ".png", ".gif", ".webp"];

    [BindProperty]
    public string? QueryString { get; set; }

    public List<SelectListItem> MemberGradeList { get; set; } = [];

    [BindProperty]
    public InputModel Input { get; set; } = new();

    public sealed class InputModel
    {
        [DisplayName("회원등급")]
        public int? MemberGradeID { get; set; }

        [DisplayName("이메일")]
        [Required(ErrorMessage = "{0}은(는) 필수입니다.")]
        [EmailAddress(ErrorMessage = "올바른 이메일 형식이 아닙니다.")]
        [StringLength(60, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
        public string Email { get; set; } = default!;

        [DisplayName("별명")]
        [Required(ErrorMessage = "{0}은(는) 필수입니다.")]
        [StringLength(20, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
        public string? Name { get; set; }

        [DisplayName("비밀번호")]
        [Required(ErrorMessage = "{0}은(는) 필수입니다.")]
        [MinLength(4, ErrorMessage = "{0}은(는) {1}자 이상 입력하세요.")]
        public string Password { get; set; } = default!;

        [DisplayName("성")]
        [StringLength(20, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
        public string? FirstName { get; set; }

        [DisplayName("이름")]
        [StringLength(40, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
        public string? LastName { get; set; }

        [DisplayName("자기소개")]
        [StringLength(1000, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
        public string? Intro { get; set; }

        [DisplayName("한마디")]
        [StringLength(50, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
        public string? Summary { get; set; }

        [DisplayName("연락처")]
        [StringLength(15)]
        public string? Phone { get; set; }

        [DisplayName("성별")]
        public Gender? Gender { get; set; }

        [DisplayName("생년월일")]
        public DateOnly? Birthday { get; set; }

        [DisplayName("사진")]
        [AllowedExtensions("jpg,jpeg,png,gif,webp", ErrorMessage = "이미지 형식은 jpg, jpeg, png, gif, webp 파일이어야 합니다.")]
        public IFormFile? Thumb { get; set; }

        [DisplayName("아이콘")]
        [AllowedExtensions("jpg,jpeg,png,gif,webp", ErrorMessage = "이미지 형식은 jpg, jpeg, png, gif, webp 파일이어야 합니다.")]
        public IFormFile? Icon { get; set; }

        [DisplayName("이메일 인증")]
        public bool IsEmailVerified { get; set; }

        [DisplayName("본인 인증")]
        public bool IsAuthCertified { get; set; }

        [DisplayName("차단 여부")]
        public bool IsDenied { get; set; }

        [DisplayName("관리자 여부")]
        public bool IsAdmin { get; set; }

        [DisplayName("탈퇴 여부")]
        public bool IsWithdraw { get; set; }

        // YouTube 채널 정보
        [DisplayName("YouTube SID")]
        [StringLength(24, MinimumLength = 24, ErrorMessage = "{0}은(는) {1}자여야 합니다.")]
        public string? YouTubeSID { get; set; }

        [DisplayName("YouTube 이름")]
        [StringLength(200, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
        public string? YouTubeName { get; set; }

        [DisplayName("YouTube 핸들")]
        [StringLength(30, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
        public string? YouTubeHandle { get; set; }

        [DisplayName("YouTube 주소")]
        [StringLength(255, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
        public string? YouTubeUrl { get; set; }
    }

    public async Task OnGetAsync(CancellationToken ct)
    {
        await LoadMemberGradeList(ct);
        QueryString = Request.QueryString.ToString();
    }

    public async Task<IActionResult> OnPostAsync(CancellationToken ct)
    {
        try
        {
            if (!ModelState.IsValid)
            {
                throw new Exception(ModelState.GetErrorMessages());
            }

            // 파일 저장 (PageModel에서 처리)
            string? thumbUrl = null;
            string? iconUrl = null;

            if (Input.Thumb is not null)
            {
                var thumbPath = new FileStoragePath(UploadTarget.Upload, UploadFolder.MemberThumb, 0);
                thumbUrl = (await fileStorage.SaveFileAsync(Input.Thumb, thumbPath, AllowedFileExtensions, ct))?.Url;
            }

            if (Input.Icon is not null)
            {
                var iconPath = new FileStoragePath(UploadTarget.Upload, UploadFolder.MemberIcon, 0);
                iconUrl = (await fileStorage.SaveFileAsync(Input.Icon, iconPath, AllowedFileExtensions, ct))?.Url;
            }

            await mediator.Send(new CreateMember.Command(
                Input.MemberGradeID,
                Input.Email,
                Input.Name,
                Input.Password,
                Input.FirstName,
                Input.LastName,
                Input.Intro,
                Input.Summary,
                Input.Phone,
                Input.Birthday,
                Input.Gender,
                thumbUrl,
                iconUrl,
                Input.IsEmailVerified,
                Input.IsAuthCertified,
                Input.IsDenied,
                Input.IsAdmin,
                Input.IsWithdraw,
                Input.YouTubeSID,
                Input.YouTubeName,
                Input.YouTubeHandle,
                Input.YouTubeUrl
            ), ct);

            TempData["SuccessMessage"] = "회원이 등록되었습니다.";
            return RedirectToPage("Index");
        }
        catch (Exception e)
        {
            TempData["ErrorMessages"] = e.Message;
        }

        await LoadMemberGradeList(ct);
        return Page();
    }

    private async Task LoadMemberGradeList(CancellationToken ct)
    {
        var grades = await mediator.Send(new GetMemberGrades.Query(), ct);

        MemberGradeList = [.. grades.List.Select(g => new SelectListItem
        {
            Value = g.ID.ToString(),
            Text = g.KorName
        })];
    }
}