using Microsoft.AspNetCore.SignalR;
using RobotNet.Script.Shares.Dashboard;
using RobotNet.ScriptManager.Data;
using RobotNet.ScriptManager.Hubs;
using System;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace RobotNet.ScriptManager.Services;

public class DashboardPublisher(DashboardConfig Config, IServiceProvider ServiceProvider, IConfiguration Configuration, IHubContext<DashboardHub> DashboardHub, ILogger<DashboardPublisher> Logger) : BackgroundService
{
    private readonly int UpdateTime = Configuration.GetValue<int>("Dashboard:UpdateTimeMilliSeconds", 5000);
    private readonly int CycleDate = Configuration.GetValue<int>("Dashboard:CycleDate", 7);

    private static TaktTimeMissionDto GetTaktTime(InstanceMission[] missions, DateTime date)
    {
        TaktTimeMissionDto taktTime = new() { Label = date.ToString("dd/MM/yyyy") };
        if (missions.Length > 0)
        {
            double TaktTimeAll = 0;
            foreach (var mission in missions)
            {
                var time = mission.StopedAt - mission.CreatedAt;
                if (time.TotalMinutes > 0)
                {
                    TaktTimeAll += time.TotalMinutes;
                    if (time.TotalMinutes < taktTime.Min || taktTime.Min == 0) taktTime.Min = time.TotalMinutes;
                    if (time.TotalMinutes > taktTime.Max || taktTime.Max == 0) taktTime.Max = time.TotalMinutes;
                }
            }
            taktTime.Average = TaktTimeAll / missions.Length;
        }
        return taktTime;
    }

    private bool IsMissionInConfig(string missionName)
    {
        return Config.MissionNames.Length == 0 || Config.MissionNames.Contains(missionName);
    }

    public DashboardDto GetData()
    {
        using var scope = ServiceProvider.CreateScope();
        var MissionDb = scope.ServiceProvider.GetRequiredService<ScriptManagerDbContext>();
        List<DailyPerformanceDto> TotalMissionPerformance = [];
        List<TaktTimeMissionDto> TaktTimeMissions = [];
        var startDate = DateTime.Today.Date.AddDays(-CycleDate);
        for (var i = startDate; i <= DateTime.Today.Date; i = i.AddDays(1))
        {
            var missions = MissionDb.InstanceMissions.Where(im => im.CreatedAt.Date == i.Date).ToList();
            missions = [.. missions.Where(im => IsMissionInConfig(im.MissionName))];
            var completedMissions = missions.Where(im => im.Status == Script.Shares.MissionStatus.Completed).ToList();
            var errorMissions = missions.Where(im => im.Status == Script.Shares.MissionStatus.Error).ToList();
            TotalMissionPerformance.Add(new DailyPerformanceDto
            {
                Label = i.ToString("dd/MM/yyyy"),
                Completed = completedMissions.Count,
                Error = errorMissions.Count,
                Other = missions.Count - completedMissions.Count - errorMissions.Count,
            });
            TaktTimeMissions.Add(GetTaktTime([.. completedMissions], i));
        }
        DailyPerformanceDto TodayPerformance = TotalMissionPerformance[^1];
        DailyPerformanceDto ThisWeekPerformance = new()
        {
            Completed = TotalMissionPerformance.Sum(dp => dp.Completed),
            Error = TotalMissionPerformance.Sum(dp => dp.Error),
            Other = TotalMissionPerformance.Sum(dp => dp.Other),
        };

        var toDayMissions = MissionDb.InstanceMissions.Where(im => im.CreatedAt.Date == DateTime.Today.Date).ToList();
        toDayMissions = [.. toDayMissions.Where(im => IsMissionInConfig(im.MissionName))];
        var toDaycompletedMissions = toDayMissions.Where(im => im.Status == Script.Shares.MissionStatus.Completed).ToList();
        var toDayerrorMissions = toDayMissions.Where(im => im.Status == Script.Shares.MissionStatus.Error).ToList();
        var toDayTaktTime = GetTaktTime([.. toDaycompletedMissions], DateTime.Today);

        DailyMissionDto DailyMission = new()
        {
            Completed = toDaycompletedMissions.Count,
            Error = toDayerrorMissions.Count,
            Total = toDayMissions.Count,
            CompletedRate = toDayMissions.Count > 0 ? (int)((toDaycompletedMissions.Count * 100.0 / toDayMissions.Count) + 0.5) : 0,
            TaktTimeMin = toDayTaktTime.Min,
            TaktTimeAverage = toDayTaktTime.Average,
            TaktTimeMax = toDayTaktTime.Max,
            RobotOnline = 1,
        };


        return new()
        {
            TaktTimeMissions = [.. TaktTimeMissions],
            ThisWeekPerformance = ThisWeekPerformance,
            TodayPerformance = TodayPerformance,
            TotalMissionPerformance = [.. TotalMissionPerformance],
            DailyMission = DailyMission,
        };
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        await Task.Yield();
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                await Task.WhenAll(DashboardHub.Clients.All.SendAsync("DashboardDataUpdated", GetData(), cancellationToken: stoppingToken), Task.Delay(UpdateTime, stoppingToken));
            }
            catch (Exception ex)
            {
                Logger.LogWarning("Dashboard Publisher xảy ra lỗi: {ex}", ex.Message);
            }
        }
    }
}
