using Microsoft.EntityFrameworkCore;
using RR3CommunityServer.Data;
using RR3CommunityServer.Models;

namespace RR3CommunityServer.Services;

public class SessionService : ISessionService
{
    private readonly RR3DbContext _context;

    public SessionService(RR3DbContext context)
    {
        _context = context;
    }

    public async Task<string> CreateSession(string? synergyId = null)
    {
        var sessionId = Guid.NewGuid().ToString();
        var session = new Session
        {
            SessionId = sessionId,
            SynergyId = synergyId,
            CreatedAt = DateTime.UtcNow,
            ExpiresAt = DateTime.UtcNow.AddHours(24)
        };

        _context.Sessions.Add(session);
        await _context.SaveChangesAsync();
        return sessionId;
    }

    public async Task<bool> ValidateSession(string sessionId)
    {
        var session = await _context.Sessions
            .FirstOrDefaultAsync(s => s.SessionId == sessionId);

        return session != null && session.ExpiresAt > DateTime.UtcNow;
    }

    public async Task<string?> GetSynergyIdFromSession(string sessionId)
    {
        var session = await _context.Sessions
            .FirstOrDefaultAsync(s => s.SessionId == sessionId);

        return session?.SynergyId;
    }
}

public class UserService : IUserService
{
    private readonly RR3DbContext _context;

    public UserService(RR3DbContext context)
    {
        _context = context;
    }

    public async Task<string> GetOrCreateDeviceId(string? existingDeviceId, string hardwareId)
    {
        if (!string.IsNullOrEmpty(existingDeviceId))
        {
            var existing = await _context.Devices
                .FirstOrDefaultAsync(d => d.DeviceId == existingDeviceId);

            if (existing != null)
            {
                existing.LastSeenAt = DateTime.UtcNow;
                await _context.SaveChangesAsync();
                return existing.DeviceId;
            }
        }

        var deviceId = Guid.NewGuid().ToString();
        var device = new Device
        {
            DeviceId = deviceId,
            HardwareId = hardwareId,
            CreatedAt = DateTime.UtcNow,
            LastSeenAt = DateTime.UtcNow
        };

        _context.Devices.Add(device);
        await _context.SaveChangesAsync();
        return deviceId;
    }

    public async Task<string> ValidateDeviceId(string deviceId)
    {
        var device = await _context.Devices
            .FirstOrDefaultAsync(d => d.DeviceId == deviceId);

        if (device != null)
        {
            device.LastSeenAt = DateTime.UtcNow;
            await _context.SaveChangesAsync();
            return "valid";
        }

        return "invalid";
    }

    public async Task<string> GetOrCreateAnonUid()
    {
        return await Task.FromResult(Guid.NewGuid().ToString());
    }

    public async Task<string> GetOrCreateSynergyId(string deviceId)
    {
        var user = await _context.Users
            .FirstOrDefaultAsync(u => u.DeviceId == deviceId);

        if (user != null)
        {
            return user.SynergyId;
        }

        var synergyId = $"SYN-{Guid.NewGuid():N}";
        user = new User
        {
            SynergyId = synergyId,
            DeviceId = deviceId,
            CreatedAt = DateTime.UtcNow
        };

        _context.Users.Add(user);
        await _context.SaveChangesAsync();
        return synergyId;
    }
}

public class CatalogService : ICatalogService
{
    private readonly RR3DbContext _context;

    public CatalogService(RR3DbContext context)
    {
        _context = context;
    }

    public async Task<List<Models.CatalogItem>> GetAvailableItems()
    {
        var items = await _context.CatalogItems
            .Where(c => c.Available)
            .ToListAsync();
        
        return items.Select(e => new Models.CatalogItem
        {
            itemId = e.Sku,
            sku = e.Sku,
            name = e.Name,
            description = e.Type,
            category = e.Type,
            price = e.Price,
            currency = "USD"
        }).ToList();
    }

    public async Task<List<CatalogCategory>> GetCategories()
    {
        var items = await _context.CatalogItems
            .Where(c => c.Available)
            .ToListAsync();
        
        var categories = items.GroupBy(i => i.Type)
            .Select(g => new CatalogCategory
            {
                categoryId = g.Key,
                name = g.Key,
                itemIds = g.Select(i => i.Sku).ToList()
            }).ToList();

        return categories;
    }

    public async Task<string> GetDownloadUrl(string itemId)
    {
        return await Task.FromResult($"https://localhost:5001/downloads/{itemId}");
    }
}

public class DrmService : IDrmService
{
    private readonly RR3DbContext _context;

    public DrmService(RR3DbContext context)
    {
        _context = context;
    }

    public async Task<string> GenerateNonce()
    {
        return await Task.FromResult(Convert.ToBase64String(Guid.NewGuid().ToByteArray()));
    }

    public async Task<List<PurchasedItem>> GetPurchasedItems(string synergyId)
    {
        var purchases = await _context.Purchases
            .Where(p => p.SynergyId == synergyId)
            .ToListAsync();

        return purchases.Select(p => new PurchasedItem
        {
            itemId = p.ItemId,
            sku = p.Sku,
            orderId = p.OrderId,
            purchaseTime = new DateTimeOffset(p.PurchaseTime).ToUnixTimeSeconds(),
            token = p.Token
        }).ToList();
    }

    public async Task<bool> VerifyAndRecordPurchase(string synergyId, PurchaseVerificationRequest request)
    {
        // For community server, we accept all purchases
        var purchase = new Purchase
        {
            SynergyId = synergyId,
            ItemId = request.sku,
            Sku = request.sku,
            OrderId = request.orderId,
            PurchaseTime = DateTime.UtcNow,
            Token = request.receipt
        };

        _context.Purchases.Add(purchase);
        await _context.SaveChangesAsync();
        return true;
    }
}
