// EN: Staff Controller for staff management.
// VI: Controller Staff để quản lý nhân viên.

using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using MerchantService.API.Application.Commands.Staff;
using MerchantService.API.Application.Queries.Staff;

namespace MerchantService.API.Controllers;

/// <summary>
/// EN: Controller for merchant staff management.
/// VI: Controller để quản lý nhân viên của merchant.
/// </summary>
[ApiController]
[Route("api/v1/merchants/me/staff")]
[Authorize]
public class StaffController : MerchantBaseController
{
    private readonly IMediator _mediator;
    private readonly ILogger<StaffController> _logger;

    public StaffController(IMediator mediator, ILogger<StaffController> logger)
    {
        _mediator = mediator;
        _logger = logger;
    }

    /// <summary>
    /// EN: Get current merchant's staff list.
    /// VI: Lấy danh sách nhân viên của merchant hiện tại.
    /// </summary>
    [HttpGet]
    [ProducesResponseType(typeof(IReadOnlyList<StaffDto>), StatusCodes.Status200OK)]
    public async Task<IActionResult> GetMyStaff()
    {
        var userId = GetCurrentUserId();
        var result = await _mediator.Send(new GetMyStaffQuery(userId));
        return Ok(result);
    }

    /// <summary>
    /// EN: Create a staff member directly as Active (owner already created IAM account).
    /// VI: Tạo nhân viên trực tiếp Active (chủ DN đã tạo tài khoản IAM).
    /// </summary>
    [HttpPost("create-active")]
    [ProducesResponseType(typeof(InviteStaffResult), StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> CreateActiveStaff([FromBody] CreateActiveStaffRequest request)
    {
        try
        {
            var ownerUserId = GetCurrentUserId();
            var command = new CreateActiveStaffCommand
            {
                OwnerUserId = ownerUserId,
                UserId = request.UserId,
                Email = request.Email,
                Role = request.Role,
                ShopId = request.ShopId,
                FirstName = request.FirstName,
                LastName = request.LastName
            };
            var result = await _mediator.Send(command);
            _logger.LogInformation("Staff created active: {Email} with userId {UserId}", request.Email, request.UserId);
            return CreatedAtAction(nameof(GetMyStaff), result);
        }
        catch (Domain.Exceptions.DomainException ex)
        {
            return BadRequest(new { message = ex.Message });
        }
    }

    /// <summary>
    /// EN: Invite a new staff member.
    /// VI: Mời nhân viên mới.
    /// </summary>
    [HttpPost("invite")]
    [ProducesResponseType(typeof(InviteStaffResult), StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> InviteStaff([FromBody] InviteStaffRequest request)
    {
        try
        {
            var userId = GetCurrentUserId();
            var command = new InviteStaffCommand
            {
                UserId = userId,
                Email = request.Email,
                Role = request.Role,
                ShopId = request.ShopId,
                BranchId = request.BranchId,
                FirstName = request.FirstName,
                LastName = request.LastName
            };
            var result = await _mediator.Send(command);
            _logger.LogInformation("Staff invited: {Email}", request.Email);
            return CreatedAtAction(nameof(GetMyStaff), result);
        }
        catch (Domain.Exceptions.DomainException ex)
        {
            return BadRequest(new { message = ex.Message });
        }
    }

    /// <summary>
    /// EN: Update a staff member.
    /// VI: Cập nhật nhân viên.
    /// </summary>
    [HttpPut("{staffId:guid}")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> UpdateStaff(Guid staffId, [FromBody] UpdateStaffRequest request)
    {
        try
        {
            var userId = GetCurrentUserId();
            var command = new UpdateStaffCommand
            {
                UserId = userId,
                StaffId = staffId,
                EmployeeCode = request.EmployeeCode,
                Phone = request.Phone,
                Role = request.Role,
                FirstName = request.FirstName,
                LastName = request.LastName,
                Address = request.Address,
                ProfilePhotoUrl = request.ProfilePhotoUrl,
                DocumentFrontUrl = request.DocumentFrontUrl,
                DocumentBackUrl = request.DocumentBackUrl
            };
            await _mediator.Send(command);
            return Ok(new { message = "Staff updated successfully" });
        }
        catch (Domain.Exceptions.DomainException ex) when (ex.Message.Contains("not found"))
        {
            return NotFound(new { message = ex.Message });
        }
        catch (Domain.Exceptions.DomainException ex) when (ex.Message.Contains("permission"))
        {
            return StatusCode(StatusCodes.Status403Forbidden, new { message = ex.Message });
        }
    }

    /// <summary>
    /// EN: Delete/terminate a staff member.
    /// VI: Xóa/chấm dứt nhân viên.
    /// </summary>
    [HttpDelete("{staffId:guid}")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> DeleteStaff(Guid staffId)
    {
        try
        {
            var userId = GetCurrentUserId();
            await _mediator.Send(new DeleteStaffCommand(staffId, userId));
            return Ok(new { message = "Staff terminated successfully" });
        }
        catch (Domain.Exceptions.DomainException ex) when (ex.Message.Contains("not found"))
        {
            return NotFound(new { message = ex.Message });
        }
        catch (Domain.Exceptions.DomainException ex) when (ex.Message.Contains("permission"))
        {
            return StatusCode(StatusCodes.Status403Forbidden, new { message = ex.Message });
        }
    }
}

/// <summary>
/// EN: Controller for staff public endpoints.
/// VI: Controller cho các endpoint công khai của staff.
/// </summary>
[ApiController]
[Route("api/v1/staff")]
[Authorize]
public class StaffPublicController : MerchantBaseController
{
    private readonly IMediator _mediator;
    private readonly ILogger<StaffPublicController> _logger;

    public StaffPublicController(IMediator mediator, ILogger<StaffPublicController> logger)
    {
        _mediator = mediator;
        _logger = logger;
    }

    /// <summary>
    /// EN: Get available staff roles.
    /// VI: Lấy danh sách vai trò nhân viên có sẵn.
    /// </summary>
    [HttpGet("roles")]
    [AllowAnonymous]
    [ProducesResponseType(typeof(IReadOnlyList<StaffRoleDto>), StatusCodes.Status200OK)]
    public async Task<IActionResult> GetRoles()
    {
        var result = await _mediator.Send(new GetStaffRolesQuery());
        return Ok(result);
    }

    /// <summary>
    /// EN: Accept a staff invitation.
    /// VI: Chấp nhận lời mời làm nhân viên.
    /// </summary>
    [HttpPost("accept-invite")]
    [ProducesResponseType(typeof(AcceptInviteResult), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> AcceptInvite([FromBody] AcceptInviteRequest request)
    {
        try
        {
            var userId = GetCurrentUserId();
            var command = new AcceptInviteCommand
            {
                UserId = userId,
                InvitationToken = request.InvitationToken,
                PinCode = request.PinCode
            };
            var result = await _mediator.Send(command);
            _logger.LogInformation("Staff invitation accepted: {StaffId}", result.StaffId);
            return Ok(result);
        }
        catch (Domain.Exceptions.DomainException ex)
        {
            return BadRequest(new { message = ex.Message });
        }
    }

    /// <summary>
    /// EN: Lookup staff profile by email — used by BFF to resolve staff identity.
    /// VI: Tìm staff profile theo email — BFF dùng để resolve staff identity.
    /// </summary>
    [HttpGet("lookup")]
    public async Task<IActionResult> LookupByEmail([FromQuery] string email)
    {
        if (string.IsNullOrEmpty(email))
            return BadRequest(new { success = false, message = "Email is required" });

        var staffRepo = HttpContext.RequestServices.GetRequiredService<MerchantService.Domain.AggregatesModel.MerchantStaffAggregate.IMerchantStaffRepository>();
        var staff = await staffRepo.GetByEmailAsync(email);
        if (staff == null)
            return NotFound(new { success = false, message = "Staff not found" });

        Guid? shopId = null;
        if (staff.ShopAssignments.Any())
            shopId = staff.ShopAssignments.First().ShopId;

        return Ok(new { success = true, data = new
        {
            staffId = staff.Id,
            userId = staff.UserId,
            email = staff.Email,
            firstName = staff.FirstName,
            lastName = staff.LastName,
            shopId,
            merchantId = staff.MerchantId
        }});
    }
}

#region Request Models

public record CreateActiveStaffRequest
{
    public Guid UserId { get; init; }
    public string Email { get; init; } = null!;
    public string Role { get; init; } = "Cashier";
    public Guid? ShopId { get; init; }
    public string? FirstName { get; init; }
    public string? LastName { get; init; }
}

public record InviteStaffRequest
{
    public string Email { get; init; } = null!;
    public string Role { get; init; } = "Cashier";
    public Guid? ShopId { get; init; }
    public Guid? BranchId { get; init; }
    public string? FirstName { get; init; }
    public string? LastName { get; init; }
}

public record UpdateStaffRequest
{
    public string? EmployeeCode { get; init; }
    public string? Phone { get; init; }
    public string? Role { get; init; }
    public string? FirstName { get; init; }
    public string? LastName { get; init; }
    public string? Address { get; init; }
    public string? ProfilePhotoUrl { get; init; }
    public string? DocumentFrontUrl { get; init; }
    public string? DocumentBackUrl { get; init; }
}

public record AcceptInviteRequest
{
    public string InvitationToken { get; init; } = null!;
    public string PinCode { get; init; } = null!;
}

#endregion
