using Microsoft.Extensions.Logging;
using ReportingServices.Shared.Models.ProductionReport;
using ReportingServices.Shared.ViewModels.ProductionReport;

namespace ReportingServices.Shared.HelperClasses
{
    public static class DailyReportHelper
    {
        private static readonly string _dailyRptFilePath = "wwwroot/Assets/DailyReportInfo.json";
        private static readonly string _SLLFilePath = "wwwroot/Assets/SLLTools.json";

        public static DailyReport SetUpDailyReport(ILogger logger, string baseUrlScrapeDb)
        {
            DailyReport report = new();

            try
            {
                report.SLLTools = JsonFileHandler.LoadJSONFile<List<SLLTool>>(_SLLFilePath);
                report.ManualReportEntries = JsonFileHandler.LoadJSONFile<ManualReportEntries>(_dailyRptFilePath);

            }
            catch (Exception ex)
            {
                logger.LogError(ex, "Failed to load JsonFiles.");
                logger.LogInformation("SLL File Path: {path}", _SLLFilePath);
                logger.LogInformation("Manual Report Entries File Path: {path}", _dailyRptFilePath);
            }

            List<string> cleanTools = new()
            {
                "AHPS",
                "AKRION1",
                "CB3",
                "MES",
                "SRD 1",
                "SRD 2"
            };

            List<string> metrologyTools = new()
            {
                "ASET",
                "BIORAD2",
                "BIORAD3",
                "BIORAD4",
                "BIORAD5",
                "CDE2",
                "CDE3",
                "CDE5",
                "FLEXUS",
                "HGCV1",
                "HGCV2",
                "HGCV3",
                "SRP"
            };

            List<Reactor> reactors = ApiCaller.GetApi<List<Reactor>>(baseUrlScrapeDb + "Reactors").Result;

            List<Task<List<ReactorEvent>>> toolEvents = new();
            List<Task<ToolEvent>> cleanEvents = new();
            List<Task<ToolEvent>> metrologyEvents = new();

            Task<YieldInformation> task1 = null;
            Task<YieldInformation> task2 = null;
            Task<QuarterlyTargets> targets = null;
            Task<List<RDS>> rds = null;

            try
            {
                foreach (Reactor reactor in reactors)
                {
                    toolEvents.Add(ApiCaller.GetApi<List<ReactorEvent>>(baseUrlScrapeDb + "ReactorEvents?startDate=" + report.StartDate.ToString() +
                        "&endDate=" + DateTime.Now.ToString() + "&reactorNumber=" + reactor.ReactorNumber + "&reactorType=" + reactor.Type));
                }

                foreach (string tool in cleanTools)
                {
                    cleanEvents.Add(ApiCaller.GetApi<ToolEvent>(baseUrlScrapeDb + "ToolEvents?toolID=" + tool));
                }

                foreach (string tool in metrologyTools)
                {
                    metrologyEvents.Add(ApiCaller.GetApi<ToolEvent>(baseUrlScrapeDb + "ToolEvents?toolID=" + tool));
                }

                task1 = ApiCaller.GetApi<YieldInformation>(baseUrlScrapeDb + "ReactorOuts?startDate=" + report.StartDate.ToString() + "&endDate=" + DateTime.Now.ToString());
                task2 = ApiCaller.GetApi<YieldInformation>(baseUrlScrapeDb + "ReactorOuts?startDate=" + report.StartDate.AddDays(-7).ToString() + "&endDate=" + report.StartDate.ToString());
                targets = ApiCaller.GetApi<QuarterlyTargets>(baseUrlScrapeDb + "Targets");
                rds = ApiCaller.GetApi<List<RDS>>(baseUrlScrapeDb + "RDS?date=" + report.StartDate.ToString());
            }
            catch (Exception ex)
            {
                logger.LogCritical(ex, "Failed to send get requests to scrapedb endpoints.");
            }

            try
            {
                report.QuarterlyTargets = targets.Result;
                report.SetRDSInfo(rds.Result);
                report.SetReactorInfo(reactors, GetUnscheduledReactors(report));

                foreach (var task in toolEvents)
                {
                    report.ToolEvents.Add(new ToolEventView(task.Result, 
                        report.StartDate.ToString(), DateTime.Now.ToString(), task.Result[0].REACT_NO, 
                        reactors.FirstOrDefault(x => x.ReactorNumber == int.Parse(task.Result[0].REACT_NO)).Type));
                }

                report.ToolEvents = report.ToolEvents
                    .Where(x => x.Reactor != "100" && x.Reactor != "101" && x.Reactor != "47")
                    .OrderBy(x => x.Reactor)
                    .ToList();

                foreach (Task<ToolEvent> task in cleanEvents)
                    report.CleanEvents.Add(task.Result);

                foreach (Task<ToolEvent> task in metrologyEvents)
                    report.MetrologyEvents.Add(task.Result);

                report.CleanEvents = report.CleanEvents.Where(x => (x.TOOL_MODE != "PROD" || x.TOOL_MODE_DESC != "Production") && x.TOOL_MODE != "OUT").ToList();
                report.MetrologyEvents = report.MetrologyEvents.Where(x => (x.TOOL_MODE != "PROD" || x.TOOL_MODE_DESC != "Production") && x.TOOL_MODE != "OUT").ToList();

                report.CurrentWeek.SetYieldInformation(task1.Result, report.QuarterlyTargets);
                report.PreviousWeek.SetYieldInformation(task2.Result, report.QuarterlyTargets);
            }
            catch (Exception ex)
            {
                logger.LogCritical(ex, "Failed to retrieve data back from Scrape DB endpoints.");
            }

            report.ReverseLists();

            ManualReportEntries entries = report.ManualReportEntries;
            List<SLLTool> sll = report.SLLTools;

            try
            {
                JsonFileHandler.SaveJSONFile(entries, _dailyRptFilePath);
                JsonFileHandler.SaveJSONFile(sll, _SLLFilePath);
            }
            catch (Exception ex)
            {
                logger.LogCritical(ex, "Failed to save data back to JSON files.");
            }

            return report;
        }

        public static List<int> GetUnscheduledReactors(DailyReport report)
        {
            List<int> reactors = new();

            foreach (ToolEventView tool in report.ToolEvents)
            {
                if (!tool.IsInProduction)
                {
                    reactors.Add(int.Parse(tool.Reactor));
                }
            }

            return reactors;
        }
    }
}
