using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Knot.Shared.Kernel.Services;
using Knot.Shared.Infrastructure.Persistence;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;

namespace Knot.Shared.Infrastructure.Statistics;

public class StatisticsService : IStatisticsService
{
    private readonly SystemDbContext _db;
    private readonly IMemoryCache _cache;

    private const string CacheKey = "dashboard_stats";

    public StatisticsService(SystemDbContext db, IMemoryCache cache)
    {
        _db = db;
        _cache = cache;
    }

    public async Task<DashboardStatsDto> GetDashboardStatsAsync(CancellationToken cancellationToken = default)
    {
        // 10 second caching to allow fast UI updates while still preventing DB overload
        if (_cache.TryGetValue(CacheKey, out DashboardStatsDto cached))
        {
            return cached!;
        }

        var latestStat = await _db.DailyStats
            .OrderByDescending(s => s.Date)
            .FirstOrDefaultAsync(cancellationToken);

        var history = await _db.DailyStats
            .OrderByDescending(s => s.Date)
            .Take(30)
            .Select(s => new ActivityStatDto
            {
                Date = s.Date,
                Messages = s.TotalMessages,
                FilesSize = s.TotalFilesSize
            })
            .ToListAsync(cancellationToken);

        var totalUsers = await _db.Database.GetDbConnection().CreateCommand().QueryTotalUsersAsync(); // Faked for simplicity without direct Identity reference

        long totalDiskSpace = 5L * 1024 * 1024 * 1024 * 1024; // Fallback
        long freeSpace = 0;
        try
        {
            var drive = new System.IO.DriveInfo("/");
            if (drive.IsReady)
            {
                totalDiskSpace = drive.TotalSize;
                freeSpace = drive.AvailableFreeSpace;
            }
            else
            {
                drive = new System.IO.DriveInfo(System.IO.Directory.GetCurrentDirectory());
                totalDiskSpace = drive.TotalSize;
                freeSpace = drive.AvailableFreeSpace;
            }
        }
        catch { }

        var usedSpace = latestStat?.TotalFilesSize ?? 0;

        long onlineUsersCount = _cache.TryGetValue("Global_OnlineUsersCount", out int count) ? count : 0;
        long offlineUsersCount = totalUsers - onlineUsersCount;
        if (offlineUsersCount < 0)
        {
            offlineUsersCount = 0;
        }

        var stats = new DashboardStatsDto
        {
            StorageUsedBytes = usedSpace,
            StorageLimitBytes = freeSpace > 0 ? usedSpace + freeSpace : totalDiskSpace,
            OnlineUsers = onlineUsersCount,
            OfflineUsers = offlineUsersCount,
            TotalUsers = totalUsers,
            ActivityTimeline = history
        };

        _cache.Set(CacheKey, stats, TimeSpan.FromSeconds(10));

        return stats;
    }
}

// Temporary internal extensions for cross-module Db fetching during demonstration
internal static class SqlExtensions
{
    public static async Task<long> QueryTotalUsersAsync(this System.Data.IDbCommand cmd)
    {
        try
        {
            cmd.CommandText = "SELECT COUNT(*) FROM identity.\"Users\"";
            if (cmd.Connection?.State != System.Data.ConnectionState.Open)
            {
                await ((System.Data.Common.DbConnection)cmd.Connection!).OpenAsync();
            }

            var result = await ((System.Data.Common.DbCommand)cmd).ExecuteScalarAsync();
            return Convert.ToInt64(result);
        }
        catch
        {
            return 0; // Fallback
        }
    }
}
