using Microsoft.Extensions.Logging;
using ReportingServices.Shared.HelperClasses;
using ReportingServices.Shared.ViewModels.ProductionReport;
using System.Data;
using System.Reflection;

namespace ReportingServices.Desktop
{
    public partial class DailyReport : Form
    {

        private DataTable currentWeek = new();
        private DataTable previousWeek = new();

        private readonly ILogger<Form1> _logger;
        private readonly string _dailyRptFilePath = "wwwroot/Assets/DailyReportInfo.json";
        private readonly string _toolStateOwnerFilePath = "wwwroot/Assets/ToolStates.json";
        private readonly string _baseFTUrl;
        private readonly string _baseDBUrl;

        public DailyReport(ILogger<Form1> logger)
        {
            _logger = logger;
            _baseFTUrl = "http://mestsa008:50201/api/";
            _baseDBUrl = "https://localhost:7196/api/";

            _logger.LogInformation("Base FabTime Address: {baseUrl}", _baseFTUrl);
            _logger.LogInformation("Base Database Address: {baseUrl}", _baseDBUrl);

            InitializeComponent();

            string baseFabTimeUrl = _baseFTUrl + "FabTime/";
            string baseScrapeDbUrl = _baseDBUrl + "ScrapeDB/";

            try
            {
                Shared.ViewModels.ProductionReport.DailyReport dailyReport = DailyReportHelper.SetUpDailyReport(_logger, baseFabTimeUrl, baseScrapeDbUrl);
                Dictionary<string, List<string>> toolStateOwners = JsonFileHandler.LoadJSONFile<Dictionary<string, List<string>>>(_toolStateOwnerFilePath);

                dailyReport.ToolStatesByOwner = toolStateOwners;

                SetupWeekView(dailyReport.CurrentWeek, currentWeek);
                SetupWeekView(dailyReport.PreviousWeek, previousWeek);

                dgvCurrentWeek.DataSource = currentWeek;
                dgvPreviousWeek.DataSource = previousWeek;
            }
            catch (Exception ex)
            {
                _logger.LogCritical(ex, "Failed to load report");
            }
        }

        public void SetupWeekView(YieldStatistics rpt, DataTable dt)
        {
            dt.Columns.Add("SIOperations");
            dt.Columns.Add("Monday");
            dt.Columns.Add("Tuesday");
            dt.Columns.Add("Wednesday");
            dt.Columns.Add("Thursday");
            dt.Columns.Add("Friday");
            dt.Columns.Add("Saturday");
            dt.Columns.Add("Sunday");
            dt.Columns.Add("Weekly Total");
            dt.Columns.Add("Comment");

            AddDates(rpt, dt);
            AddTargets(rpt, dt);
            AddOuts(rpt, dt);
            AddYieldedWafers(rpt, dt);
            AddCustomerScrap(rpt, dt);
            AddManufacturingScrap(rpt, dt);
            AddProductionScrap(rpt, dt);
            AddYield(rpt, dt);
            AddDeltaToCommit(rpt, dt);
            AddDeltaToTarget(rpt, dt);
            AddNeededTarget(rpt, dt);
        }

        public void AddDates(YieldStatistics rpt, DataTable dt)
        {
            DataRow dr = dt.NewRow();

            for (int i = 0; i < 7; i++)
            {
                dr[1 + i] = rpt.StartDate.AddDays(i).ToString("MM/dd/yyyy");
            }

            dt.Rows.Add(dr);
        }

        public void AddTargets(YieldStatistics rpt, DataTable dt)
        {
            DataRow dr = dt.NewRow();

            dr["SIOperations"] = "Commited Target to meet Shipment Requirements";

            for (int i = 0; i < 7; i++)
            {
                dr[1 + i] = string.Format("{0:#,###}", rpt.DailyPlanWafers);
            }

            dr["WeeklyTotal"] = string.Format("{0:##,###}", rpt.DailyPlanWafers * 7);
            dr["Comment"] = "Number updated quarterly";

            dt.Rows.Add(dr);
        }

        public void AddOuts(YieldStatistics rpt, DataTable dt)
        {
            int counter = 0;

            DataRow dr = dt.NewRow();

            dr["SIOperations"] = "Actual Reactor Out";

            for (int i = 0; i < 7; i++)
            {
                if (i < rpt.OutsByDay.Count)
                {
                    dr[1 + i] = string.Format("{0:#,###}", rpt.OutsByDay[i].TotalWafers);

                    counter += rpt.OutsByDay[i].TotalWafers;
                }
            }

            dr["WeeklyTotal"] = string.Format("{0:##,###}", counter);
            dr["Comment"] = "Before Scrap";

            dt.Rows.Add(dr);
        }

        public void AddYieldedWafers(YieldStatistics rpt, DataTable dt)
        {
            int counter = 0;

            DataRow dr = dt.NewRow();

            dr["SIOperations"] = "Actual Yielded Wafers Out";

            for (int i = 0; i < 7; i++)
            {
                if (i < rpt.OutsByDay.Count)
                {
                    dr[1 + i] = string.Format("{0:#,###}", rpt.OutsByDay[i].TotalWafers - rpt.ScrapByDay[i].TOT_REJ_WFRS - rpt.ScrapByDay[i].TW_PROD);

                    counter += rpt.OutsByDay[i].TotalWafers - rpt.ScrapByDay[i].TOT_REJ_WFRS - rpt.ScrapByDay[i].TW_PROD;
                }
            }

            dr["WeeklyTotal"] = string.Format("{0:##,###}", counter);
            dr["Comment"] = "After Scrap";

            dt.Rows.Add(dr);
        }

        public void AddCustomerScrap(YieldStatistics rpt, DataTable dt)
        {
            int counter = 0;

            DataRow dr = dt.NewRow();

            dr["SIOperations"] = "Customer Scrap";

            for (int i = 0; i < 7; i++)
            {
                if (i < rpt.OutsByDay.Count)
                {
                    dr[1 + i] = string.Format("{0:#,###}", rpt.ScrapByDay[i].TOT_REJ_CUST);

                    counter += rpt.ScrapByDay[i].TOT_REJ_CUST;
                }
            }

            dr["WeeklyTotal"] = string.Format("{0:##,###}", counter);

            dt.Rows.Add(dr);
        }

        public void AddManufacturingScrap(YieldStatistics rpt, DataTable dt)
        {
            int counter = 0;

            DataRow dr = dt.NewRow();

            dr["SIOperations"] = "Manufacturing Scrap";

            for (int i = 0; i < 7; i++)
            {
                if (i < rpt.OutsByDay.Count)
                {
                    dr[1 + i] = string.Format("{0:#,###}", rpt.ScrapByDay[i].TOT_REJ_MANU);

                    counter += rpt.ScrapByDay[i].TOT_REJ_MANU;
                }
            }

            dr["WeeklyTotal"] = string.Format("{0:##,###}", counter);

            dt.Rows.Add(dr);
        }

        public void AddProductionScrap(YieldStatistics rpt, DataTable dt)
        {
            int counter = 0;

            DataRow dr = dt.NewRow();

            dr["SIOperations"] = "Production Scrap";

            for (int i = 0; i < 7; i++)
            {
                if (i < rpt.OutsByDay.Count)
                {
                    dr[1 + i] = string.Format("{0:#,###}", rpt.ScrapByDay[i].TW_PROD);

                    counter += rpt.ScrapByDay[i].TW_PROD;
                }
            }

            dr["WeeklyTotal"] = string.Format("{0:##,###}", counter);

            dt.Rows.Add(dr);
        }

        public void AddYield(YieldStatistics rpt, DataTable dt)
        {
            int totalOuts = 0;
            int totalScrap = 0;

            DataRow dr = dt.NewRow();

            dr["SIOperations"] = "Yield";

            for (int i = 0; i < 7; i++)
            {
                if (i < rpt.OutsByDay.Count)
                {
                    float yield = ((float)rpt.OutsByDay[i].TotalWafers - (float)rpt.ScrapByDay[i].TOT_REJ_WFRS) / (float)rpt.OutsByDay[i].TotalWafers;

                    dr[1 + i] = string.Format("{0:P2}", rpt.ScrapByDay[i].TW_PROD);

                    totalOuts += rpt.OutsByDay[i].TotalWafers;
                    totalScrap += rpt.ScrapByDay[i].TOT_REJ_CUST + rpt.ScrapByDay[i].TOT_REJ_MANU;
                }
            }

            dr["WeeklyTotal"] = string.Format("{0:P2}", (float)(totalOuts - totalScrap) / (float)totalOuts);
            dr["Comment"] = "After Scrap";

            dt.Rows.Add(dr);
        }

        public void AddDeltaToCommit(YieldStatistics rpt, DataTable dt)
        {
            int counter = 0;

            DataRow dr = dt.NewRow();

            dr["SIOperations"] = "Delta to commit";

            for (int i = 0; i < 7; i++)
            {
                if (i < rpt.OutsByDay.Count)
                {
                    int delta = rpt.OutsByDay[i].TotalWafers - rpt.ScrapByDay[i].TOT_REJ_WFRS - rpt.DailyPlanWafers;
                        
                    dr[1 + i] = string.Format("{0:#,###}", delta);

                    counter += delta;
                }
            }

            dr["WeeklyTotal"] = string.Format("{0:##,###}", counter);
            dr["Comment"] = "Difference to commitment";

            dt.Rows.Add(dr);
        }

        public void AddDeltaToTarget(YieldStatistics rpt, DataTable dt)
        {
            int counter = 0;

            DataRow dr = dt.NewRow();

            dr["SIOperations"] = "Delta to the Plan";

            for (int i = 0; i < 7; i++)
            {
                if (i < rpt.OutsByDay.Count)
                {
                    int delta = rpt.OutsByDay[i].TotalWafers - rpt.ScrapByDay[i].TOT_REJ_WFRS - rpt.DailyPlanWafers;

                    dr[1 + i] = string.Format("{0:#,###}", delta);

                    counter += delta;
                }
            }

            dr["WeeklyTotal"] = string.Format("{0:##,###}", counter);
            dr["Comment"] = "Difference to Target";

            dt.Rows.Add(dr);
        }

        public void AddNeededTarget(YieldStatistics rpt, DataTable dt)
        {
            DataRow dr = dt.NewRow();

            dr["SIOperations"] = "Wafers Needed to make QTR";

            for (int i = 0; i < 7; i++)
            {
                if (i < rpt.OutsByDay.Count)
                {
                    dr[1 + i] = string.Format("{0:#,###}", rpt.DailyPlanWafers);
                }
            }

            dr["WeeklyTotal"] = string.Format("{0:##,###}", rpt.DailyPlanWafers * 7);
            dr["Comment"] = "Number updated Weekly";

            dt.Rows.Add(dr);
        }

        private void btnPrevious_Click(object sender, EventArgs e)
        {
            btnNext.Visible = true;
            btnPrevious.Visible = false;

            dgvCurrentWeek.Visible = false;
            dgvPreviousWeek.Visible = true;
        }

        private void btnNext_Click(object sender, EventArgs e)
        {
            btnNext.Visible = false;
            btnPrevious.Visible = true;

            dgvCurrentWeek.Visible = true;
            dgvPreviousWeek.Visible = false;
        }
    }
}