using System.ComponentModel.DataAnnotations;
using Jiaowu.Api.Domain.Academic;
using Jiaowu.Api.Domain.Identity;
using Jiaowu.Api.Infrastructure.Auth;
using Jiaowu.Api.Infrastructure.Caching;
using Jiaowu.Api.Infrastructure.Persistence;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace Jiaowu.Api.Controllers;

[ApiController]
[Authorize(Roles = SystemRoles.Student)]
[Route("api/student/profile")]
public sealed class StudentProfileController(
    AppDbContext db,
    ICurrentUserDataScope currentUserDataScope,
    IAppCache cache) : ControllerBase
{
    [HttpGet]
    public async Task<ActionResult<StudentProfileDto>> Get(
        CancellationToken cancellationToken)
    {
        var userId = currentUserDataScope.Current.UserId;
        var profile = await db.Students.AsNoTracking()
            .Where(x => x.UserId == userId)
            .Select(x => new StudentProfileDto(
                x.StudentNumber,
                x.Name,
                x.AdministrativeClass!.Name,
                x.AdministrativeClass.Major!.Name,
                x.AdministrativeClass.Major.College!.Name,
                x.EnrollmentYear,
                x.EnrollmentDate,
                x.Status,
                x.Gender,
                x.DateOfBirth,
                x.EnglishName,
                x.IdCardNumber,
                x.Nationality,
                x.Ethnicity,
                x.PoliticalStatus,
                x.NativePlace,
                x.HouseholdAddress,
                x.CurrentAddress,
                x.PostalCode,
                x.Phone,
                x.Email,
                x.Qq,
                x.WeChat,
                x.EmergencyContactName,
                x.EmergencyContactRelationship,
                x.EmergencyContactPhone,
                x.SpecialTags,
                x.SpecialNeeds,
                x.Biography))
            .SingleOrDefaultAsync(cancellationToken);

        return profile is null ? NotFound() : Ok(profile);
    }

    [HttpPut]
    public async Task<IActionResult> Update(
        StudentProfileUpdateRequest request,
        CancellationToken cancellationToken)
    {
        var userId = currentUserDataScope.Current.UserId;
        var student = await db.Students.SingleOrDefaultAsync(
            x => x.UserId == userId,
            cancellationToken);
        if (student is null) return NotFound();

        student.Gender = request.Gender;
        student.DateOfBirth = request.DateOfBirth;
        student.EnglishName = Normalize(request.EnglishName);
        student.IdCardNumber = Normalize(request.IdCardNumber);
        student.Nationality = Normalize(request.Nationality);
        student.Ethnicity = Normalize(request.Ethnicity);
        student.PoliticalStatus = Normalize(request.PoliticalStatus);
        student.NativePlace = Normalize(request.NativePlace);
        student.HouseholdAddress = Normalize(request.HouseholdAddress);
        student.CurrentAddress = Normalize(request.CurrentAddress);
        student.PostalCode = Normalize(request.PostalCode);
        student.Phone = Normalize(request.Phone);
        student.Email = Normalize(request.Email);
        student.Qq = Normalize(request.Qq);
        student.WeChat = Normalize(request.WeChat);
        student.EmergencyContactName = Normalize(request.EmergencyContactName);
        student.EmergencyContactRelationship = Normalize(
            request.EmergencyContactRelationship);
        student.EmergencyContactPhone = Normalize(request.EmergencyContactPhone);
        student.SpecialTags = Normalize(request.SpecialTags);
        student.SpecialNeeds = Normalize(request.SpecialNeeds);
        student.Biography = Normalize(request.Biography);

        await db.SaveChangesAsync(cancellationToken);
        await cache.RemoveByTagAsync(AppCacheTags.Analytics, cancellationToken);
        return NoContent();
    }

    private static string? Normalize(string? value) =>
        string.IsNullOrWhiteSpace(value) ? null : value.Trim();
}

public sealed record StudentProfileDto(
    string StudentNumber,
    string Name,
    string ClassName,
    string MajorName,
    string CollegeName,
    int EnrollmentYear,
    DateOnly EnrollmentDate,
    StudentStatus Status,
    Gender Gender,
    DateOnly? DateOfBirth,
    string? EnglishName,
    string? IdCardNumber,
    string? Nationality,
    string? Ethnicity,
    string? PoliticalStatus,
    string? NativePlace,
    string? HouseholdAddress,
    string? CurrentAddress,
    string? PostalCode,
    string? Phone,
    string? Email,
    string? Qq,
    string? WeChat,
    string? EmergencyContactName,
    string? EmergencyContactRelationship,
    string? EmergencyContactPhone,
    string? SpecialTags,
    string? SpecialNeeds,
    string? Biography);

public sealed record StudentProfileUpdateRequest(
    Gender Gender,
    DateOnly? DateOfBirth,
    [MaxLength(100)] string? EnglishName,
    [MaxLength(30)] string? IdCardNumber,
    [MaxLength(50)] string? Nationality,
    [MaxLength(50)] string? Ethnicity,
    [MaxLength(50)] string? PoliticalStatus,
    [MaxLength(100)] string? NativePlace,
    [MaxLength(300)] string? HouseholdAddress,
    [MaxLength(300)] string? CurrentAddress,
    [MaxLength(20)] string? PostalCode,
    [MaxLength(30)] string? Phone,
    [EmailAddress, MaxLength(100)] string? Email,
    [MaxLength(30)] string? Qq,
    [MaxLength(60)] string? WeChat,
    [MaxLength(50)] string? EmergencyContactName,
    [MaxLength(30)] string? EmergencyContactRelationship,
    [MaxLength(30)] string? EmergencyContactPhone,
    [MaxLength(300)] string? SpecialTags,
    [MaxLength(1000)] string? SpecialNeeds,
    [MaxLength(1000)] string? Biography);
