using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using NostrServices.Services;

namespace NostrServices.Controllers;

[Route("/api/v1/relays")]
public class RelaysController : Controller
{
    private readonly RedisStore _database;

    public RelaysController(RedisStore database)
    {
        _database = database;
    }

    [Produces("application/json")]
    [HttpPost]
    public async Task<IEnumerable<Client.RelayDistance>> GetCloseRelays([FromBody] LatLonReq pos, [FromQuery] int count = 5)
    {
        const int distance = 5000 * 1000; // 5,000km
        var relays = await _database.FindCloseRelays(pos.Lat, pos.Lon, distance, count);

        return relays.Select(a => a.FromDistance());
    }

    [Produces("application/json")]
    [HttpGet("top")]
    public async Task<IEnumerable<Client.RelayDistance>> GetTop([FromQuery] int count = 10)
    {
        var top = await _database.CountRelayUsers();
        var topSelected = top.OrderByDescending(a => a.Value).Take(count);

        var infos = await Task.WhenAll(topSelected.Select(a => _database.GetRelay(a.Key)));
        return infos.Where(a => a != default).Select(a => a!.FromInfo());
    }
}

public class LatLonReq
{
    [JsonProperty("lat")]
    public double Lat { get; init; }

    [JsonProperty("lon")]
    public double Lon { get; init; }
}

public static class RelayDistanceExtension
{
    public static Client.RelayDistance FromDistance(this RelayDistance x)
    {
        var rp = x.Relay.Positions.FirstOrDefault(a => a.IpAddress == x.IpAddress) ?? x.Relay.Positions.First();
        return new Client.RelayDistance()
        {
            Url = x.Relay.Url,
            Distance = x.Distance,
            Users = x.Relay.Users,
            Country = rp.Country,
            City = rp.City,
            Description = x.Relay.Description,
            IsPaid = x.Relay.IsPaid,
            IsWriteRestricted = x.Relay.IsWriteRestricted,
            Latitude = rp.Lat,
            Longitude = rp.Lon
        };
    }

    public static Client.RelayDistance FromInfo(this RelayInfo x)
    {
        var rp = x.Positions.First();
        return new Client.RelayDistance()
        {
            Url = x.Url,
            Distance = 0,
            Users = x.Users,
            Country = rp.Country,
            City = rp.City,
            Description = x.Description,
            IsPaid = x.IsPaid,
            IsWriteRestricted = x.IsWriteRestricted,
            Latitude = rp.Lat,
            Longitude = rp.Lon
        };
    }
}
