using FluentValidation;
using Microsoft.AspNetCore.Mvc;
using Meezi.API.Models.Crm;
using Meezi.API.Services;
using Meezi.Core.Interfaces;
using Meezi.Shared;

namespace Meezi.API.Controllers;

/// <summary>
/// Marketing SMS — bring-your-own-provider. Each café configures its OWN
/// Kavenegar API key + sender line; the platform does not sell SMS.
/// </summary>
[Route("api/cafes/{cafeId}/sms")]
public class SmsController : CafeApiControllerBase
{
    private readonly ISmsMarketingService _smsMarketingService;
    private readonly IValidator<SendSmsCampaignRequest> _campaignValidator;

    public SmsController(
        ISmsMarketingService smsMarketingService,
        IValidator<SendSmsCampaignRequest> campaignValidator)
    {
        _smsMarketingService = smsMarketingService;
        _campaignValidator = campaignValidator;
    }

    [HttpGet("settings")]
    public async Task<IActionResult> GetSettings(string cafeId, ITenantContext tenant, CancellationToken cancellationToken)
    {
        if (EnsureCafeAccess(cafeId, tenant) is { } denied) return denied;
        if (EnsureManager(tenant) is { } forbidden) return forbidden;

        var data = await _smsMarketingService.GetSettingsAsync(cafeId, cancellationToken);
        return Ok(new ApiResponse<SmsSettingsDto>(true, data));
    }

    [HttpPut("settings")]
    public async Task<IActionResult> UpdateSettings(
        string cafeId,
        [FromBody] UpdateSmsSettingsRequest request,
        ITenantContext tenant,
        CancellationToken cancellationToken)
    {
        if (EnsureCafeAccess(cafeId, tenant) is { } denied) return denied;
        if (EnsureManager(tenant) is { } forbidden) return forbidden;

        var (success, data, code, message) = await _smsMarketingService.UpdateSettingsAsync(
            cafeId, request, cancellationToken);
        if (!success)
        {
            return code switch
            {
                "NOT_FOUND" => NotFound(new ApiResponse<object>(false, null, new ApiError(code, message!))),
                _ => BadRequest(new ApiResponse<object>(false, null, new ApiError(code!, message!)))
            };
        }

        return Ok(new ApiResponse<SmsSettingsDto>(true, data));
    }

    [HttpGet("balance")]
    public async Task<IActionResult> GetBalance(string cafeId, ITenantContext tenant, CancellationToken cancellationToken)
    {
        if (EnsureCafeAccess(cafeId, tenant) is { } denied) return denied;

        var dto = await _smsMarketingService.GetBalanceAsync(cafeId, cancellationToken);
        return Ok(new ApiResponse<SmsBalanceDto>(true, dto));
    }

    [HttpGet("usage")]
    public async Task<IActionResult> GetUsage(string cafeId, ITenantContext tenant, CancellationToken cancellationToken)
    {
        if (EnsureCafeAccess(cafeId, tenant) is { } denied) return denied;

        var data = await _smsMarketingService.GetUsageAsync(cafeId, cancellationToken);
        return Ok(new ApiResponse<SmsUsageDto>(true, data));
    }

    [HttpPost("campaign")]
    public async Task<IActionResult> SendCampaign(
        string cafeId,
        [FromBody] SendSmsCampaignRequest request,
        ITenantContext tenant,
        CancellationToken cancellationToken)
    {
        if (EnsureCafeAccess(cafeId, tenant) is { } denied) return denied;

        var validation = await _campaignValidator.ValidateAsync(request, cancellationToken);
        if (!validation.IsValid) return BadRequest(ValidationError(validation));

        var (success, data, code, message) = await _smsMarketingService.SendCampaignAsync(
            cafeId, request, cancellationToken);

        if (!success)
        {
            return code switch
            {
                "SMS_NOT_CONFIGURED" => BadRequest(
                    new ApiResponse<object>(false, null, new ApiError(code, message!))),
                "NOT_FOUND" => NotFound(new ApiResponse<object>(false, null, new ApiError(code, message!))),
                _ => BadRequest(new ApiResponse<object>(false, null, new ApiError(code!, message!)))
            };
        }

        return Ok(new ApiResponse<SmsCampaignResult>(true, data));
    }
}
