using Asp.Versioning;
using MediatR;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
using IamService.API.Application.Common;
using IamService.API.Application.Commands.Organizations;
using IamService.API.Application.Queries.Organizations;

namespace IamService.API.Controllers;

/// <summary>
/// EN: Organizations management controller.
/// VI: Controller quản lý tổ chức.
/// </summary>
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/organizations")]
[Authorize(AuthenticationSchemes = "Bearer")]
[Authorize(Policy = "RequireAdmin")]
[SwaggerTag("Organization management endpoints - requires Admin role")]
public class OrganizationsController : ControllerBase
{
    private readonly IMediator _mediator;
    private readonly ILogger<OrganizationsController> _logger;

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

    /// <summary>
    /// EN: Get organization by ID.
    /// VI: Lấy tổ chức theo ID.
    /// </summary>
    [HttpGet("{id:guid}")]
    [SwaggerOperation(Summary = "Get organization by ID", OperationId = "GetOrganizationById")]
    [SwaggerResponse(StatusCodes.Status200OK, "Organization found", typeof(ApiResponse<OrganizationResponse>))]
    [SwaggerResponse(StatusCodes.Status404NotFound, "Organization not found")]
    [ProducesResponseType(typeof(ApiResponse<OrganizationResponse>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> GetOrganizationById(
        [FromRoute] Guid id,
        CancellationToken cancellationToken = default)
    {
        var result = await _mediator.Send(new GetOrganizationByIdQuery(id), cancellationToken);

        if (result == null)
            return NotFound(ApiResponse<OrganizationResponse>.Fail("ORG_NOT_FOUND", $"Organization with ID {id} not found."));

        return Ok(ApiResponse<OrganizationResponse>.Ok(MapToResponse(result)));
    }

    /// <summary>
    /// EN: Get organization by slug.
    /// VI: Lấy tổ chức theo slug.
    /// </summary>
    [HttpGet("slug/{slug}")]
    [SwaggerOperation(Summary = "Get organization by slug", OperationId = "GetOrganizationBySlug")]
    [SwaggerResponse(StatusCodes.Status200OK, "Organization found", typeof(ApiResponse<OrganizationResponse>))]
    [SwaggerResponse(StatusCodes.Status404NotFound, "Organization not found")]
    [ProducesResponseType(typeof(ApiResponse<OrganizationResponse>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> GetOrganizationBySlug(
        [FromRoute] string slug,
        CancellationToken cancellationToken = default)
    {
        var result = await _mediator.Send(new GetOrganizationBySlugQuery(slug), cancellationToken);

        if (result == null)
            return NotFound(ApiResponse<OrganizationResponse>.Fail("ORG_NOT_FOUND", $"Organization with slug '{slug}' not found."));

        return Ok(ApiResponse<OrganizationResponse>.Ok(MapToResponse(result)));
    }

    /// <summary>
    /// EN: Create a new organization.
    /// VI: Tạo tổ chức mới.
    /// </summary>
    [HttpPost]
    [SwaggerOperation(Summary = "Create organization", OperationId = "CreateOrganization")]
    [SwaggerResponse(StatusCodes.Status201Created, "Organization created", typeof(ApiResponse<OrganizationResponse>))]
    [SwaggerResponse(StatusCodes.Status400BadRequest, "Invalid request")]
    [SwaggerResponse(StatusCodes.Status409Conflict, "Organization with slug already exists")]
    [ProducesResponseType(typeof(ApiResponse<OrganizationResponse>), StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    public async Task<IActionResult> CreateOrganization(
        [FromBody] CreateOrganizationRequest request,
        CancellationToken cancellationToken = default)
    {
        try
        {
            var command = new CreateOrganizationCommand(
                request.Name,
                request.Slug,
                request.Description,
                request.ParentOrganizationId);

            var result = await _mediator.Send(command, cancellationToken);

            var response = new OrganizationResponse
            {
                Id = result.Id,
                Name = result.Name,
                Slug = result.Slug,
                Description = result.Description,
                ParentOrganizationId = result.ParentOrganizationId,
                Status = result.Status,
                CreatedAt = result.CreatedAt
            };

            return CreatedAtAction(nameof(GetOrganizationById), new { id = result.Id }, ApiResponse<OrganizationResponse>.Ok(response));
        }
        catch (Exception ex) when (ex.Message.Contains("already exists"))
        {
            return Conflict(ApiResponse<OrganizationResponse>.Fail("SLUG_EXISTS", ex.Message));
        }
    }

    /// <summary>
    /// EN: Update organization.
    /// VI: Cập nhật tổ chức.
    /// </summary>
    [HttpPut("{id:guid}")]
    [SwaggerOperation(Summary = "Update organization", OperationId = "UpdateOrganization")]
    [SwaggerResponse(StatusCodes.Status200OK, "Organization updated", typeof(ApiResponse<OrganizationResponse>))]
    [SwaggerResponse(StatusCodes.Status404NotFound, "Organization not found")]
    [ProducesResponseType(typeof(ApiResponse<OrganizationResponse>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> UpdateOrganization(
        [FromRoute] Guid id,
        [FromBody] UpdateOrganizationRequest request,
        CancellationToken cancellationToken = default)
    {
        try
        {
            var command = new UpdateOrganizationCommand(id, request.Name, request.Description);
            var result = await _mediator.Send(command, cancellationToken);

            return Ok(ApiResponse<OrganizationResponse>.Ok(new OrganizationResponse
            {
                Id = result.Id,
                Name = result.Name,
                Description = result.Description,
                UpdatedAt = result.UpdatedAt
            }));
        }
        catch (Exception ex) when (ex.Message.Contains("not found"))
        {
            return NotFound(ApiResponse<OrganizationResponse>.Fail("ORG_NOT_FOUND", ex.Message));
        }
    }

    /// <summary>
    /// EN: Archive (soft delete) organization.
    /// VI: Lưu trữ (xóa mềm) tổ chức.
    /// </summary>
    [HttpDelete("{id:guid}")]
    [SwaggerOperation(Summary = "Archive organization", OperationId = "ArchiveOrganization")]
    [SwaggerResponse(StatusCodes.Status200OK, "Organization archived")]
    [SwaggerResponse(StatusCodes.Status400BadRequest, "Cannot archive organization with children")]
    [SwaggerResponse(StatusCodes.Status404NotFound, "Organization not found")]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> ArchiveOrganization(
        [FromRoute] Guid id,
        CancellationToken cancellationToken = default)
    {
        try
        {
            await _mediator.Send(new ArchiveOrganizationCommand(id), cancellationToken);
            return Ok(ApiResponse<object>.Ok(new { Message = "Organization archived successfully." }));
        }
        catch (Exception ex) when (ex.Message.Contains("not found"))
        {
            return NotFound(ApiResponse<object>.Fail("ORG_NOT_FOUND", ex.Message));
        }
        catch (Exception ex) when (ex.Message.Contains("children"))
        {
            return BadRequest(ApiResponse<object>.Fail("HAS_CHILDREN", ex.Message));
        }
    }

    /// <summary>
    /// EN: Get organization hierarchy.
    /// VI: Lấy phân cấp tổ chức.
    /// </summary>
    [HttpGet("{id:guid}/hierarchy")]
    [SwaggerOperation(Summary = "Get organization hierarchy", OperationId = "GetOrganizationHierarchy")]
    [SwaggerResponse(StatusCodes.Status200OK, "Hierarchy returned", typeof(ApiResponse<IEnumerable<OrganizationResponse>>))]
    [ProducesResponseType(typeof(ApiResponse<IEnumerable<OrganizationResponse>>), StatusCodes.Status200OK)]
    public async Task<IActionResult> GetOrganizationHierarchy(
        [FromRoute] Guid id,
        CancellationToken cancellationToken = default)
    {
        var result = await _mediator.Send(new GetOrganizationHierarchyQuery(id), cancellationToken);
        return Ok(ApiResponse<IEnumerable<OrganizationResponse>>.Ok(result.Select(MapToResponse)));
    }

    /// <summary>
    /// EN: Get child organizations.
    /// VI: Lấy tổ chức con.
    /// </summary>
    [HttpGet("{id:guid}/children")]
    [SwaggerOperation(Summary = "Get child organizations", OperationId = "GetChildOrganizations")]
    [SwaggerResponse(StatusCodes.Status200OK, "Children returned", typeof(ApiResponse<IEnumerable<OrganizationResponse>>))]
    [ProducesResponseType(typeof(ApiResponse<IEnumerable<OrganizationResponse>>), StatusCodes.Status200OK)]
    public async Task<IActionResult> GetChildOrganizations(
        [FromRoute] Guid id,
        CancellationToken cancellationToken = default)
    {
        var result = await _mediator.Send(new GetChildOrganizationsQuery(id), cancellationToken);
        return Ok(ApiResponse<IEnumerable<OrganizationResponse>>.Ok(result.Select(MapToResponse)));
    }

    private static OrganizationResponse MapToResponse(OrganizationDto dto) => new()
    {
        Id = dto.Id,
        Name = dto.Name,
        Slug = dto.Slug,
        Description = dto.Description,
        ParentOrganizationId = dto.ParentOrganizationId,
        Status = dto.Status,
        CreatedAt = dto.CreatedAt,
        UpdatedAt = dto.UpdatedAt
    };
}

#region Request/Response Models

/// <summary>
/// EN: Request body for creating organization.
/// VI: Request body để tạo tổ chức.
/// </summary>
public class CreateOrganizationRequest
{
    /// <example>Acme Corporation</example>
    public string Name { get; set; } = string.Empty;

    /// <example>acme-corp</example>
    public string Slug { get; set; } = string.Empty;

    /// <example>A leading technology company</example>
    public string? Description { get; set; }

    public Guid? ParentOrganizationId { get; set; }
}

/// <summary>
/// EN: Request body for updating organization.
/// VI: Request body để cập nhật tổ chức.
/// </summary>
public class UpdateOrganizationRequest
{
    public string Name { get; set; } = string.Empty;
    public string? Description { get; set; }
}

/// <summary>
/// EN: Organization response model.
/// VI: Model response cho tổ chức.
/// </summary>
public class OrganizationResponse
{
    public Guid Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public string Slug { get; set; } = string.Empty;
    public string? Description { get; set; }
    public Guid? ParentOrganizationId { get; set; }
    public string? Status { get; set; }
    public DateTime CreatedAt { get; set; }
    public DateTime? UpdatedAt { get; set; }
}

#endregion
