using AdsManagerService.API.Application.Commands;
using AdsManagerService.API.Application.Queries;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace AdsManagerService.API.Controllers;

/// <summary>
/// EN: API Controller for managing advertising campaigns.
/// VI: API Controller quản lý chiến dịch quảng cáo.
/// </summary>
[ApiController]
[Authorize]
[Route("api/v1/ads-manager/campaigns")]
[Produces("application/json")]
public class CampaignsController : ControllerBase
{
    private readonly IMediator _mediator;
    private readonly ILogger<CampaignsController> _logger;

    public CampaignsController(IMediator mediator, ILogger<CampaignsController> logger)
    {
        _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    /// <summary>
    /// EN: Create a new campaign.
    /// VI: Tạo chiến dịch mới.
    /// </summary>
    [HttpPost]
    [ProducesResponseType(StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<ActionResult<Guid>> CreateCampaign([FromBody] CreateCampaignCommand command)
    {
        _logger.LogInformation("Creating campaign for advertiser {AdvertiserId}", command.AdvertiserId);

        var campaignId = await _mediator.Send(command);

        return CreatedAtAction(nameof(GetCampaignById), new { id = campaignId }, new { success = true, data = campaignId });
    }

    /// <summary>
    /// EN: List campaigns with filtering and pagination.
    /// VI: Liệt kê chiến dịch với lọc và phân trang.
    /// </summary>
    [HttpGet]
    [ProducesResponseType(typeof(ListCampaignsResult), StatusCodes.Status200OK)]
    public async Task<ActionResult<ListCampaignsResult>> ListCampaigns(
        [FromQuery] Guid? advertiserId,
        [FromQuery] string? status,
        [FromQuery] string? objective,
        [FromQuery] string? searchTerm,
        [FromQuery] int page = 1,
        [FromQuery] int pageSize = 20)
    {
        var query = new ListCampaignsQuery
        {
            AdvertiserId = advertiserId,
            Status = status,
            Objective = objective,
            SearchTerm = searchTerm,
            Page = page,
            PageSize = pageSize
        };

        var result = await _mediator.Send(query);
        return Ok(new { success = true, data = result });
    }

    /// <summary>
    /// EN: Get campaign by ID.
    /// VI: Lấy chiến dịch theo ID.
    /// </summary>
    [HttpGet("{id}")]
    [ProducesResponseType(typeof(CampaignDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<ActionResult<CampaignDto>> GetCampaignById(Guid id)
    {
        var campaign = await _mediator.Send(new GetCampaignByIdQuery { CampaignId = id });

        if (campaign == null)
            return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Campaign not found" } });

        return Ok(new { success = true, data = campaign });
    }

    /// <summary>
    /// EN: Update campaign information.
    /// VI: Cập nhật thông tin chiến dịch.
    /// </summary>
    [HttpPut("{id}")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> UpdateCampaign(Guid id, [FromBody] UpdateCampaignRequest request)
    {
        var command = new UpdateCampaignCommand
        {
            CampaignId = id,
            Name = request.Name,
            Description = request.Description
        };

        var result = await _mediator.Send(command);

        if (!result)
            return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Campaign not found" } });

        return NoContent();
    }

    /// <summary>
    /// EN: Activate a campaign to start serving ads.
    /// VI: Kích hoạt chiến dịch để bắt đầu chạy quảng cáo.
    /// </summary>
    [HttpPost("{id}/activate")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> ActivateCampaign(Guid id)
    {
        _logger.LogInformation("Activating campaign {CampaignId}", id);

        var result = await _mediator.Send(new ActivateCampaignCommand { CampaignId = id });

        if (!result)
            return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Campaign not found" } });

        return NoContent();
    }

    /// <summary>
    /// EN: Pause a campaign.
    /// VI: Tạm dừng chiến dịch.
    /// </summary>
    [HttpPost("{id}/pause")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> PauseCampaign(Guid id)
    {
        _logger.LogInformation("Pausing campaign {CampaignId}", id);

        var result = await _mediator.Send(new PauseCampaignCommand { CampaignId = id });

        if (!result)
            return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Campaign not found" } });

        return NoContent();
    }

    /// <summary>
    /// EN: Delete (archive) a campaign.
    /// VI: Xóa (lưu trữ) chiến dịch.
    /// </summary>
    [HttpDelete("{id}")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> DeleteCampaign(Guid id)
    {
        _logger.LogInformation("Deleting campaign {CampaignId}", id);

        var result = await _mediator.Send(new DeleteCampaignCommand { CampaignId = id });

        if (!result)
            return NotFound(new { success = false, error = new { code = "NOT_FOUND", message = "Campaign not found" } });

        return NoContent();
    }
}

/// <summary>
/// EN: Request model for updating campaign.
/// VI: Request model cập nhật chiến dịch.
/// </summary>
public record UpdateCampaignRequest
{
    public string Name { get; init; } = null!;
    public string? Description { get; init; }
}
