using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Ikar.Server.Data;
using Ikar.Server.Data.Entities;
using Ikar.Server.Infrastructure;
using Ikar.Server.Infrastructure.Auth;
using Ikar.Shared;

namespace Ikar.Server.Controllers;

[ApiController]
[Authorize]
[Route("api/[controller]")]
public sealed class PushController(IkarDbContext dbContext) : ControllerBase
{
    [HttpGet("devices")]
    public async Task<ActionResult<IReadOnlyList<PushDeviceDto>>> GetDevices(CancellationToken cancellationToken)
    {
        var userId = User.GetRequiredUserId();
        var devices = await dbContext.PushDevices
            .AsNoTracking()
            .Where(x => x.UserId == userId)
            .ToListAsync(cancellationToken);

        return Ok(devices
            .OrderByDescending(x => x.UpdatedAt)
            .Select(x => x.ToDto())
            .ToList());
    }

    [HttpPost("devices")]
    public async Task<ActionResult<PushDeviceDto>> RegisterDevice(
        RegisterPushDeviceRequest request,
        CancellationToken cancellationToken)
    {
        var userId = User.GetRequiredUserId();
        var installationId = request.InstallationId?.Trim() ?? string.Empty;
        var deviceToken = request.DeviceToken?.Trim() ?? string.Empty;
        if (request.Platform == PushPlatform.Unknown ||
            string.IsNullOrWhiteSpace(installationId) ||
            string.IsNullOrWhiteSpace(deviceToken))
        {
            return ValidationProblem("Platform, installationId and deviceToken are required.");
        }

        var clientVersion = ClientVersionRequestReader.Read(Request);
        var device = await dbContext.PushDevices
            .SingleOrDefaultAsync(x => x.InstallationId == installationId, cancellationToken);

        if (device is null)
        {
            device = new PushDevice
            {
                UserId = userId,
                Platform = request.Platform,
                InstallationId = installationId,
                DeviceToken = deviceToken,
                DeviceName = NormalizeDeviceName(request.DeviceName),
                NotificationsEnabled = request.NotificationsEnabled,
                UpdatedAt = DateTimeOffset.UtcNow
            };
            ClientVersionRequestReader.Apply(device, clientVersion);

            dbContext.PushDevices.Add(device);
        }
        else
        {
            device.UserId = userId;
            device.Platform = request.Platform;
            device.DeviceToken = deviceToken;
            device.DeviceName = NormalizeDeviceName(request.DeviceName);
            device.NotificationsEnabled = request.NotificationsEnabled;
            device.UpdatedAt = DateTimeOffset.UtcNow;
            ClientVersionRequestReader.Apply(device, clientVersion);
        }

        await dbContext.SaveChangesAsync(cancellationToken);
        return Ok(device.ToDto());
    }

    [HttpDelete("devices/{installationId}")]
    public async Task<IActionResult> UnregisterDevice(string installationId, CancellationToken cancellationToken)
    {
        var userId = User.GetRequiredUserId();
        var normalizedInstallationId = installationId?.Trim() ?? string.Empty;
        if (string.IsNullOrWhiteSpace(normalizedInstallationId))
        {
            return NotFound();
        }

        var device = await dbContext.PushDevices
            .SingleOrDefaultAsync(
                x => x.InstallationId == normalizedInstallationId &&
                     x.UserId == userId,
                cancellationToken);

        if (device is null)
        {
            return NotFound();
        }

        dbContext.PushDevices.Remove(device);
        await dbContext.SaveChangesAsync(cancellationToken);
        return NoContent();
    }

    private static string? NormalizeDeviceName(string? deviceName)
    {
        var normalized = deviceName?.Trim();
        return string.IsNullOrWhiteSpace(normalized) ? null : normalized;
    }
}
