using Microsoft.Data.SqlClient;
using ReportingServices.Shared.Models.PlanningReport;
using ReportingServices.Shared.Models.ProductionReport;
using System.Data;

namespace ReportingServices.Shared.Repositories
{
    public class ScrapeDatabaseRepository : IScrapeDatabaseRepository
    {
        private SqlConnection _connection;
        private readonly string _connectionString;

        public ScrapeDatabaseRepository()
        {
            _connectionString = "Server=MESSV01EC.EC.LOCAL\\PROD1,53959;Database=LSL2SQL;User Id=srpadmin;Password=0okm9ijn;TrustServerCertificate=true";
        }

        public void OpenConnection()
        {
            if (_connection == null)
                _connection = new SqlConnection(_connectionString);

            if (_connection.State != ConnectionState.Open)
                _connection.Open();
        }

        public void CloseConnection()
        {
            if (_connection.State != ConnectionState.Closed)
                _connection.Close();
        }

        public int GetNumberOfPartChanges(string startDate, string endDate)
        {
            int result = 0;

            OpenConnection();

            SqlCommand cmd = _connection.CreateCommand();

            string query = "SELECT COUNT(*) FROM " +
                           "(SELECT REACTOR, COUNT(PROD_SPEC_ID) - 1 AS PCHANGE FROM " +
                           "(SELECT REACTOR, PROD_SPEC_ID, COUNT(WO) AS PSN_COUNT FROM RDS WHERE DATE_OUT BETWEEN @startDate AND @endDate GROUP BY REACTOR, PROD_SPEC_ID) AS t " +
                           "GROUP BY REACTOR) AS l WHERE PCHANGE > 0";

            cmd.CommandText = query;
            cmd.Parameters.AddWithValue("@startDate", startDate);
            cmd.Parameters.AddWithValue("@endDate", endDate);

            using (SqlDataReader reader = cmd.ExecuteReader())
            {
                reader.Read();

                result = int.Parse(reader[0].ToString());
            }

            cmd.Dispose();

            CloseConnection();

            return result;
        }

        public List<ScrapByDay> GetScrapByDay(List<ReactorOutsByRDS> outs)
        {
            List<ScrapByDay> scrap = new();
            string rdsNumbers = "";

            foreach (ReactorOutsByRDS rout in outs)
                rdsNumbers = rdsNumbers + "'" + rout.RDS_NO + "', ";

            rdsNumbers = rdsNumbers.Substring(0, rdsNumbers.Length - 2);

            OpenConnection();

            SqlCommand cmd = _connection.CreateCommand();

            string query = "SELECT " +
                            "  DATE_OUT," +
                            "  SUM(CUST_TOT_REJ) AS TOT_REJ_CUST," +
                            "  SUM(LSL_TOT_REJ) AS TOT_REJ_MANU," +
                            "  SUM(TW_PROD) AS TW_PROD " +
                            "FROM RDS " +
                            "WHERE SEQ IN (" + rdsNumbers + ") " +
                            "GROUP BY DATE_OUT " +
                            "ORDER BY 1 DESC";

            cmd.CommandText = query;

            using (SqlDataReader reader = cmd.ExecuteReader())
            {
                while (reader.Read() && reader[0].ToString() != "1/1/1900 12:00:00 AM")
                    scrap.Add(new ScrapByDay
                    {
                        StartDate = reader[0].ToString(),
                        TW_PROD = int.Parse(reader[3].ToString()),
                        TOT_REJ_CUST = int.Parse(reader[1].ToString()),
                        TOT_REJ_MANU = int.Parse(reader[2].ToString()),
                        TOT_REJ_WFRS =
                        int.Parse(reader[1].ToString()) + int.Parse(reader[2].ToString())
                    });
            }

            cmd.Dispose();

            CloseConnection();

            return scrap;
        }

        public List<ReactorPSNWORuns> GetReactorPSNWORuns(string startDate, string endDate)
        {
            List<ReactorPSNWORuns> weeklyPartChanges = new();

            OpenConnection();

            SqlCommand cmd = _connection.CreateCommand();

            string query = "SELECT REACTOR, PROD_SPEC_ID, COUNT(WO) FROM RDS " +
                            "WHERE DATE_OUT BETWEEN @startDate AND @endDate " +
                            "GROUP BY REACTOR, PROD_SPEC_ID " +
                            "ORDER BY 1";

            cmd.CommandText = query;
            cmd.Parameters.AddWithValue("@startDate", startDate);
            cmd.Parameters.AddWithValue("@endDate", endDate);

            using (SqlDataReader reader = cmd.ExecuteReader())
            {
                while (reader.Read())
                    weeklyPartChanges.Add(new ReactorPSNWORuns
                    {
                        REACTOR = reader[0].ToString(),
                        PSN = reader[1].ToString(),
                        WO_COUNT = int.Parse(reader[2].ToString())
                    });
            }

            cmd.Dispose();

            CloseConnection();

            return weeklyPartChanges;
        }

        public QuarterlyTargets GetQuarterlyTargets()
        {
            Dictionary<string, float> targets = new();

            OpenConnection();

            SqlCommand cmd = _connection.CreateCommand();

            string query = "SELECT THRU_TARGET, THRU_QTY, THRU_PCNT FROM FISCAL_QTR_TARGETS " +
                           " WHERE THRU_GROUP = 'TOT' " +
                           "   AND FISCAL_YR = " +
                           "    (SELECT FISCAL_YR FROM FISCAL_QTR " +
                           "      WHERE START_DT < SYSDATETIME() " +
                           "        AND END_DT > SYSDATETIME()) " +
                           "   AND FISCAL_QTR = " +
                           "    (SELECT FISCAL_QTR FROM FISCAL_QTR " +
                           "      WHERE START_DT < SYSDATETIME() " +
                           "        AND END_DT > SYSDATETIME()) " +
                           "UNION " +
                           "SELECT 'PlanWorkingDays' As THRU_TARGET," +
                           "       PLAN_WORKING_DAYS AS THRU_QTY," +
                           "       NULL AS THRU_PCNT" +
                           "  FROM FISCAL_QTR " +
                           " WHERE SYSDATETIME() BETWEEN START_DT AND END_DT";

            cmd.CommandText = query;

            using (SqlDataReader reader = cmd.ExecuteReader())
            {
                while(reader.Read())
                {
                    if (reader[0].ToString().ToUpper() == "YIELD")
                        targets.Add(reader[0].ToString(), float.Parse(reader[2].ToString()));
                    else if (!string.IsNullOrEmpty(reader[1].ToString()))
                        targets.Add(reader[0].ToString(), int.Parse(reader[1].ToString()));
                }
            }

            cmd.Dispose();

            CloseConnection();

            QuarterlyTargets quarterlyTargets = new()
            {
                Reactor_Outs = (int)targets["Reactor_Outs"],
                Yield_Outs = (int)targets["Yield_Outs"],
                IFX_Scrap = (int)targets["IFX_Scrap"],
                Yield = targets["Yield"],
                PlanWorkingDays = (int)targets["PlanWorkingDays"]
            };

            return quarterlyTargets;
        }

        public List<Reactor> GetReactors()
        {
            List<Reactor> reactors = new();

            OpenConnection();

            SqlCommand cmd = _connection.CreateCommand();

            string query = "SELECT " +
                           "   REACT_NO, REACT_TYPE, SUSC_POCKET_SIZE, CASE WHEN ACTIVE_LL_DISABLED <> '' THEN 'TRUE' ELSE 'FALSE' END AS \"LL_DISABLED\" " +
                           "  FROM REACTOR " +
                           " WHERE REACT_ASSIGNMENT IS NOT NULL " +
                           "   AND REACT_ASSIGNMENT <> 'Out of Service' " +
                           "   AND REACT_ASSIGNMENT<> ''";

            cmd.CommandText = query;

            using (SqlDataReader reader = cmd.ExecuteReader())
            {
                while (reader.Read())
                    reactors.Add(new Reactor
                    {
                        ReactorNumber = int.Parse(reader[0].ToString()),
                        Type = reader[1].ToString(),
                        PocketSize = reader[2].ToString(),
                        HasDisabledLoadlock = bool.Parse(reader[3].ToString())
                    });
            }

            cmd.Dispose();

            CloseConnection();

            return reactors;
        }

        public List<RDS> GetRDSForLastDay(string date)
        {
            List<RDS> rdsList = new();

            OpenConnection();

            SqlCommand cmd = _connection.CreateCommand();

            string query = "SELECT rds.REACTOR, rds.REACTOR_TYPE, rds.DATE_OUT, " +
                           "CASE WHEN lay.UL_TEMP IS NULL THEN '1000' ELSE lay.UL_TEMP END, psn.LAYER_TYPE FROM RDS " +
                           "INNER JOIN RDS_LAYER lay ON lay.RDS_NO = SEQ " +
                           "INNER JOIN PROD_SPEC psn ON rds.PROD_SPEC_ID = psn.SEQ " +
                           "WHERE DATE_OUT >= @date";

            cmd.CommandText = query;
            cmd.Parameters.AddWithValue("@date", date);

            using (SqlDataReader reader = cmd.ExecuteReader())
            {
                while (reader.Read())
                    rdsList.Add(new RDS
                    {
                        Reactor = int.Parse(reader[0].ToString()),
                        ReactorType = reader[1].ToString(),
                        DateOut = DateTime.Parse(reader[2].ToString()),
                        UnloadTemp = int.Parse(reader[3].ToString()),
                        LayerType = reader[4].ToString()
                    });
            }

            cmd.Dispose();

            CloseConnection();

            return rdsList;
        }
    }
}
