// 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 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 : ControllerBase
{
    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 result = await _mediator.Send(new GetMyStaffQuery());
        return Ok(result);
    }

    /// <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 command = new InviteStaffCommand
            {
                Email = request.Email,
                Role = request.Role,
                ShopId = request.ShopId,
                BranchId = request.BranchId
            };
            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 command = new UpdateStaffCommand
            {
                StaffId = staffId,
                EmployeeCode = request.EmployeeCode,
                Phone = request.Phone,
                Role = request.Role
            };
            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
        {
            await _mediator.Send(new DeleteStaffCommand(staffId));
            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 : ControllerBase
{
    private readonly IMediator _mediator;
    private readonly ILogger<StaffPublicController> _logger;

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

    /// <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 command = new AcceptInviteCommand
            {
                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 });
        }
    }
}

#region Request Models

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 record UpdateStaffRequest
{
    public string? EmployeeCode { get; init; }
    public string? Phone { get; init; }
    public string? Role { get; init; }
}

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

#endregion
