using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using System.Security.Claims;
using LittleShop.DTOs;
using LittleShop.Services;
namespace LittleShop.Controllers;
[ApiController]
[Route("api/push")]
public class PushNotificationController : ControllerBase
{
private readonly IPushNotificationService _pushNotificationService;
private readonly ITeleBotMessagingService _teleBotMessagingService;
public PushNotificationController(IPushNotificationService pushNotificationService, ITeleBotMessagingService teleBotMessagingService)
{
_pushNotificationService = pushNotificationService;
_teleBotMessagingService = teleBotMessagingService;
}
///
/// Get the VAPID public key for client-side push subscription
///
[HttpGet("vapid-key")]
public IActionResult GetVapidPublicKey()
{
try
{
var publicKey = _pushNotificationService.GetVapidPublicKey();
return Ok(new { publicKey });
}
catch (Exception ex)
{
return StatusCode(500, new { error = ex.Message });
}
}
///
/// Subscribe admin user to push notifications
///
[HttpPost("subscribe")]
[Authorize(AuthenticationSchemes = "Cookies", Roles = "Admin")]
public async Task Subscribe([FromBody] PushSubscriptionDto subscriptionDto)
{
try
{
var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
var username = User.FindFirst(ClaimTypes.Name)?.Value ?? User.Identity?.Name;
// Debug logging
var logger = HttpContext.RequestServices.GetRequiredService>();
logger.LogInformation("Push subscription attempt - UserIdClaim: {UserIdClaim}, Username: {Username}", userIdClaim, username);
if (string.IsNullOrEmpty(userIdClaim) || !Guid.TryParse(userIdClaim, out Guid userId))
{
return Unauthorized(new { error = "Invalid user ID", userIdClaim, username });
}
var userAgent = Request.Headers.UserAgent.ToString();
var ipAddress = HttpContext.Connection.RemoteIpAddress?.ToString();
var success = await _pushNotificationService.SubscribeUserAsync(userId, subscriptionDto, userAgent, ipAddress);
if (success)
{
return Ok(new { message = "Successfully subscribed to push notifications" });
}
else
{
return StatusCode(500, new { error = "Failed to subscribe to push notifications" });
}
}
catch (Exception ex)
{
var logger = HttpContext.RequestServices.GetRequiredService>();
logger.LogError(ex, "Push subscription error");
return StatusCode(500, new { error = ex.Message });
}
}
///
/// Subscribe customer to push notifications (for customer-facing apps)
///
[HttpPost("subscribe/customer")]
[AllowAnonymous]
public async Task SubscribeCustomer([FromBody] PushSubscriptionDto subscriptionDto, [FromQuery] Guid customerId)
{
try
{
if (customerId == Guid.Empty)
{
return BadRequest("Invalid customer ID");
}
var userAgent = Request.Headers.UserAgent.ToString();
var ipAddress = HttpContext.Connection.RemoteIpAddress?.ToString();
var success = await _pushNotificationService.SubscribeCustomerAsync(customerId, subscriptionDto, userAgent, ipAddress);
if (success)
{
return Ok(new { message = "Successfully subscribed to push notifications" });
}
else
{
return StatusCode(500, new { error = "Failed to subscribe to push notifications" });
}
}
catch (Exception ex)
{
return StatusCode(500, new { error = ex.Message });
}
}
///
/// Unsubscribe from push notifications
///
[HttpPost("unsubscribe")]
public async Task Unsubscribe([FromBody] UnsubscribeDto unsubscribeDto)
{
try
{
var success = await _pushNotificationService.UnsubscribeAsync(unsubscribeDto.Endpoint);
if (success)
{
return Ok(new { message = "Successfully unsubscribed from push notifications" });
}
else
{
return NotFound(new { error = "Subscription not found" });
}
}
catch (Exception ex)
{
return StatusCode(500, new { error = ex.Message });
}
}
///
/// Send test notification to current admin user
///
[HttpPost("test")]
[Authorize(AuthenticationSchemes = "Cookies", Roles = "Admin")]
public async Task SendTestNotification([FromBody] TestPushNotificationDto testDto)
{
try
{
var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
var success = await _pushNotificationService.SendTestNotificationAsync(userIdClaim, testDto.Title, testDto.Body);
if (success)
{
return Ok(new { message = "Test notification sent successfully" });
}
else
{
return StatusCode(500, new { error = "Failed to send test notification. Make sure you are subscribed to push notifications." });
}
}
catch (Exception ex)
{
return StatusCode(500, new { error = ex.Message });
}
}
///
/// Send broadcast notification to all admin users
///
[HttpPost("broadcast")]
[Authorize(AuthenticationSchemes = "Cookies", Roles = "Admin")]
public async Task SendBroadcastNotification([FromBody] PushNotificationDto notificationDto)
{
try
{
var success = await _pushNotificationService.SendNotificationToAllUsersAsync(notificationDto);
if (success)
{
return Ok(new { message = "Broadcast notification sent successfully" });
}
else
{
return StatusCode(500, new { error = "Failed to send broadcast notification" });
}
}
catch (Exception ex)
{
return StatusCode(500, new { error = ex.Message });
}
}
///
/// Get active push subscriptions (admin only)
///
[HttpGet("subscriptions")]
[Authorize(AuthenticationSchemes = "Cookies", Roles = "Admin")]
public async Task GetActiveSubscriptions()
{
try
{
var subscriptions = await _pushNotificationService.GetActiveSubscriptionsAsync();
var result = subscriptions.Select(s => new
{
id = s.Id,
userId = s.UserId,
customerId = s.CustomerId,
userName = s.User?.Username,
customerName = s.Customer?.TelegramDisplayName ?? s.Customer?.TelegramUsername,
subscribedAt = s.SubscribedAt,
lastUsedAt = s.LastUsedAt,
userAgent = s.UserAgent,
endpoint = s.Endpoint[..Math.Min(50, s.Endpoint.Length)] + "..." // Truncate for security
}).ToList();
return Ok(result);
}
catch (Exception ex)
{
return StatusCode(500, new { error = ex.Message });
}
}
///
/// Cleanup expired push subscriptions
///
[HttpPost("cleanup")]
[Authorize(AuthenticationSchemes = "Cookies", Roles = "Admin")]
public async Task CleanupExpiredSubscriptions()
{
try
{
var cleanedCount = await _pushNotificationService.CleanupExpiredSubscriptionsAsync();
return Ok(new { message = $"Cleaned up {cleanedCount} expired subscriptions" });
}
catch (Exception ex)
{
return StatusCode(500, new { error = ex.Message });
}
}
///
/// Get TeleBot service status
///
[HttpGet("telebot/status")]
[Authorize(AuthenticationSchemes = "Cookies", Roles = "Admin")]
public async Task GetTeleBotStatus()
{
try
{
var isAvailable = await _teleBotMessagingService.IsAvailableAsync();
return Ok(new
{
available = isAvailable,
message = isAvailable ? "TeleBot service is available" : "TeleBot service is not available"
});
}
catch (Exception ex)
{
return StatusCode(500, new { error = ex.Message });
}
}
///
/// Send test message to TeleBot customer
///
[HttpPost("telebot/test")]
[Authorize(AuthenticationSchemes = "Cookies", Roles = "Admin")]
public async Task SendTeleBotTestMessage([FromBody] TeleBotTestMessageDto testDto)
{
try
{
var success = await _teleBotMessagingService.SendTestMessageAsync(testDto.CustomerId, testDto.Message);
if (success)
{
return Ok(new { message = "TeleBot test message sent successfully" });
}
else
{
return StatusCode(500, new { error = "Failed to send TeleBot test message. Check TeleBot service status." });
}
}
catch (Exception ex)
{
return StatusCode(500, new { error = ex.Message });
}
}
}
public class UnsubscribeDto
{
public string Endpoint { get; set; } = string.Empty;
}
public class TeleBotTestMessageDto
{
public Guid CustomerId { get; set; }
public string Message { get; set; } = "This is a test message from LittleShop admin!";
}