using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.RateLimiting;
using Microsoft.EntityFrameworkCore;
using Meezi.API.Models.Public;
using Meezi.API.Services;
using Meezi.Core.Authorization;
using Meezi.Core.Interfaces;
using Meezi.Infrastructure.Data;
using Meezi.Shared;

namespace Meezi.API.Controllers;

/// <summary>
/// Push-notification endpoints for the native (Capacitor + Pushe) app.
///
///   POST /api/public/push/register    — anonymous device registration
///   POST /api/public/push/unregister  — anonymous device removal
///   POST /api/push/broadcast          — café marketing push (own topic only)
/// </summary>
public class PushController : CafeApiControllerBase
{
    private readonly IPushDeviceService _devices;
    private readonly IPushSender _sender;
    private readonly AppDbContext _db;

    public PushController(IPushDeviceService devices, IPushSender sender, AppDbContext db)
    {
        _devices = devices;
        _sender = sender;
        _db = db;
    }

    [HttpPost("api/public/push/register")]
    [AllowAnonymous]
    [EnableRateLimiting("public-read")]
    public async Task<IActionResult> Register(
        [FromBody] RegisterPushDeviceRequest request, CancellationToken ct)
    {
        if (string.IsNullOrWhiteSpace(request.Token))
            return BadRequest(new ApiResponse<object>(false, null,
                new ApiError("INVALID_TOKEN", "Device token is required.")));

        await _devices.RegisterAsync(request, ct);
        return Ok(new ApiResponse<object>(true, new { registered = true }));
    }

    [HttpPost("api/public/push/unregister")]
    [AllowAnonymous]
    [EnableRateLimiting("public-read")]
    public async Task<IActionResult> Unregister(
        [FromBody] UnregisterPushDeviceRequest request, CancellationToken ct)
    {
        await _devices.UnregisterAsync(request.Token, ct);
        return Ok(new ApiResponse<object>(true, new { unregistered = true }));
    }

    [HttpPost("api/push/broadcast")]
    public async Task<IActionResult> Broadcast(
        [FromBody] BroadcastPushRequest request,
        ITenantContext tenant,
        CancellationToken ct)
    {
        if (EnsurePermission(tenant, Permission.SendSms) is { } forbidden) return forbidden;
        if (string.IsNullOrEmpty(tenant.CafeId))
            return StatusCode(StatusCodes.Status403Forbidden,
                new ApiResponse<object>(false, null, new ApiError("FORBIDDEN", "Café context is required.")));

        // A café may only push to its OWN topic (cafe-{slug}). The client-supplied
        // topic is intentionally ignored to prevent cross-café / city-wide pushes.
        var slug = await _db.Cafes.AsNoTracking()
            .Where(c => c.Id == tenant.CafeId)
            .Select(c => c.Slug)
            .FirstOrDefaultAsync(ct);
        if (string.IsNullOrWhiteSpace(slug))
            return NotFoundError("Café not found.");

        await _sender.SendToTopicAsync($"cafe-{slug}", request.Title, request.Body, request.DeepLink, ct);
        return Ok(new ApiResponse<object>(true, new { sent = true }));
    }
}
