using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System.Reflection;
using NHibernate;
//Located at: https://data.itreetools.org/sql
using LocationSpecies.Domain;

namespace WeatherPrep
{
    class CreateOutput
    {
        //These fields are never used
        //string locDB;
        //string nationID;
        //string priPartID;
        //string secPartID;
        //string terPartID;

        double LeafAreaIndexMax;
        double Evergreen_pct;
        VEGTYPE VegetationType;
        int startYr;
        int endYr;
        double Height_WeatherStationWindSensor_m;
        double Height_TreeCanopyTop_m;

        string MeteorologicalFile_string;
        string PrecipitationFile_string;
        string LeafAreaIndex_dataBase;
        string Meteo_DatabasePath;
        string model_type;

        // Variables sent by SimulationManager.cs: 
        //MeteorologicalDataInputFile_string, PrecipitationDataInputFile_string, LocationData_Object, LeafAreaIndex_dataBase, VegetationType_class, DateYear_Start_int, DateYear_Stop_int, Meteo_DatabasePath_string

        public CreateOutput(
            double LeafAreaIndex_max, 
            double Evergreen_percent, 
            string LeafAreaIndex_dataBase_string, 
            int DateYear_Start_int, 
            int DateYear_Stop_int, 
            VEGTYPE VegetationType_class, 
            string MeteorologicalDataInputFile_string, 
            string PrecipitationDataInputFile_string, 
            string Meteo_DatabasePath_string, 
            string ModelType_string,
            double Height_WeatherStationWindSensor_t_m, 
            double Height_TreeCanopyTop_t_m)
        {
            LeafAreaIndexMax = LeafAreaIndex_max;
            Evergreen_pct = Evergreen_percent;
            VegetationType = VegetationType_class;
            Height_WeatherStationWindSensor_m = Height_WeatherStationWindSensor_t_m;
            Height_TreeCanopyTop_m = Height_TreeCanopyTop_t_m;
            startYr = DateYear_Start_int;
            endYr = DateYear_Stop_int;
            MeteorologicalFile_string = MeteorologicalDataInputFile_string;
            PrecipitationFile_string = PrecipitationDataInputFile_string;
            LeafAreaIndex_dataBase = LeafAreaIndex_dataBase_string;
            Meteo_DatabasePath = Meteo_DatabasePath_string;
            model_type = ModelType_string;
        }
        //Helper determines if extra data are available to add for January 1 or December 31 given time zone clipped data 
        private static (bool jan1Missing, bool dec31Missing) ComputeEdgePaddingFlags(IReadOnlyList<DateTime> dtList)
        {
            bool Flag_EnoughDataAvailable = dtList != null && dtList.Count >= 48;
            bool Flag_PadDataForJan1 = Flag_EnoughDataAvailable && dtList[0].Month == 1 && dtList[0].Day == 2;
            bool Flag_PadDataForDec31 = Flag_EnoughDataAvailable && dtList[dtList.Count - 1].Month == 12 && dtList[dtList.Count - 1].Day == 30;
            return (Flag_PadDataForJan1, Flag_PadDataForDec31);
        }

        // Function now works with CSV files
        public void CreateOutputFiles(ISession NHibernate_Session, Location location)
        {
            try
            {
                LocationData LocationData_Object = new LocationData(NHibernate_Session);
                ForestData forData;
                LocationData_Object.ReadLocationData(location);
                forData = new ForestData(0, LeafAreaIndexMax, Evergreen_pct, 0);

                Console.WriteLine("\nQuerying server to determine leaf on and off dates and compute meteorological outputs.");

                //call LeafAreaIndex.ProcessLAI to compute terms for LAI database, where WeatherPrepConfig.xml has values for MaxLAI,
                //...  and PctEvGrnCov, startYr, endYr, and LeafAreaIndex_dataBase is file path and name to LAI.csv
                LeafAreaIndex.ProcessLAI(forData.MaxLAI, forData.PctEvGrnCov, LocationData_Object, startYr, endYr, LeafAreaIndex_dataBase);
                //Optional console output for debbugging
                //Console.WriteLine("Leaf area index timeseries DB constructed for use in evapotranspiration calculations.");

                //SurfaceWeather_List_final is the List created in SurfaceWeather for use in writing output
                List<SurfaceWeather> SurfaceWeather_List_final = new List<SurfaceWeather>();

                //call ProcessSurfaceWeatherData to get SurfaceWeather data and return it as SurfaceWeather_List_final
                SurfaceWeather.ProcessSurfaceWeatherData(MeteorologicalFile_string, PrecipitationFile_string, LocationData_Object, LeafAreaIndex_dataBase, VegetationType, startYr, endYr, Meteo_DatabasePath, Height_WeatherStationWindSensor_m, Height_TreeCanopyTop_m, ref SurfaceWeather_List_final);

                //assign names to output files, Weather.csv, Evaporation.csv, Radiation.csv
                string weatherFile = Path.GetDirectoryName(Meteo_DatabasePath) + "\\Weather.csv";
                string evFile = Path.GetDirectoryName(Meteo_DatabasePath) + "\\Evaporation.csv";
                string srFile = Path.GetDirectoryName(Meteo_DatabasePath) + "\\Radiation.csv";

                //call CreateWeatherDatCSV to create Weather.csv output
                CreateWeatherDatCSV(SurfaceWeather_List_final, weatherFile);
                //Console output to manage expectations for upcoming program activity
                Console.WriteLine("Generating Weather, Evaporation, and Radiation data files ...");
                //Write output to user
                Console.WriteLine("The following output files were written:");
                Console.WriteLine(weatherFile);

                //call CreateEvapDatCSV to create Evaporation.csv output
                CreateEvapDatCSV(SurfaceWeather_List_final, evFile);
                Console.WriteLine(evFile);

                //call CreateSolarRadDatCSV to create Radiation.csv output
                CreateSolarRadDatCSV(SurfaceWeather_List_final, srFile);
                Console.WriteLine(srFile);

                //Note: LAIDatabase & WeatherDatabase are written to the default dirPath, defined above
                Console.WriteLine("Databases used to generate output, LAI.csv and Meteo.csv, were also provided.");

                //Write output to user
                Console.WriteLine("\nSimulation completed. Check above output files for results.");
                Console.WriteLine("Thank you for using i-Tree tools to improve the world!");
            }
            catch (Exception)
            {
                return;
            }
        }

        private string First(string p, int p_2)
        {
            return p.Substring(0, Math.Min(p.Length, p_2));
        }

        //CreateWeatherDatCSV function uses Meteo_DatabasePath from CSV file and weatherFile strings
        private void CreateWeatherDatCSV(List<SurfaceWeather> SurfaceWeather_List_final, string weatherFile)
        {
            if (SurfaceWeather_List_final == null || SurfaceWeather_List_final.Count == 0)
                throw new InvalidOperationException("SurfaceWeather_List_final is empty; cannot create Weather.csv.");

            using (StreamWriter sw = File.CreateText(weatherFile))
            {
                // Headers (same as before)
                if (model_type == "Hydro")
                {
                    sw.WriteLine("YYYYMMDD,HH:MM:SS,Temperature_Air_C(C),Temperature_DewPoint_C(C),Radiation_Net_Wpm2(W/m^2),Wind_Speed_mps(m/s),Pressure_Atmosphere_kPa(kPa),Precipitation_Rate_mph(m/h),Snow_DepthOnGround_m(m)");
                }
                else if (model_type == "Building")
                {
                    sw.WriteLine("YYYYMMDD,HH:MM:SS,Temperature_Air_C(C),Temperature_DewPoint_C(C),Radiation_Net_Wpm2(W/m^2),Wind_Speed_mps(m/s),Wind_Direction_deg(deg),Pressure_Atmosphere_kPa(kPa),Precipitation_Rate_mph(m/h),Snow_DepthOnGround_m(m)");
                }
                else if (model_type == "Hydro8")
                {
                    sw.WriteLine("YYYYMMDD,HH:MM:SS,Temperature_Air_C(C),Temperature_DewPoint_C(C),Radiation_Net_Wpm2(W/m^2),Wind_Speed_mps(m/s),Precipitation_Rate_mph(m/h),Snow_DepthOnGround_m(m)");
                }

                foreach (var rec in SurfaceWeather_List_final)
                {
                    string dateStr = rec.TimeStamp.ToString("yyyyMMdd");
                    string timeStr = rec.TimeStamp.ToString("HH':'mm':'ss");

                    if (model_type == "Hydro")
                    {
                        sw.Write(
                            dateStr + "," +
                            timeStr + "," +
                            First(rec.Tair_2m_C.ToString("0.00000000"), 11) + "," +
                            First(rec.Tdew_2m_C.ToString("0.00000000"), 11) + "," +
                            First(rec.Radiation_Net_Wpm2.ToString("0.00000000"), 11) + "," +
                            First(rec.Wspd_mps.ToString("0.00000000"), 11) + "," +
                            First(rec.AtmP_kPa.ToString("0.00000000"), 11) + "," +
                            First(rec.Ppt_1hr_m.ToString("0.00000000"), 11) + "," +
                            First(rec.SnowDepth_m.ToString("0.00000000"), 11) + "\r\n"
                        );
                    }
                    else if (model_type == "Building")
                    {
                        sw.Write(
                            dateStr + "," +
                            timeStr + "," +
                            First(rec.Tair_2m_C.ToString("0.00000000"), 11) + "," +
                            First(rec.Tdew_2m_C.ToString("0.00000000"), 11) + "," +
                            First(rec.Radiation_Net_Wpm2.ToString("0.00000000"), 11) + "," +
                            First(rec.Wspd_mps.ToString("0.00000000"), 11) + "," +
                            First(rec.Wdir_deg.ToString("0.00000000"), 11) + "," +
                            First(rec.AtmP_kPa.ToString("0.00000000"), 11) + "," +
                            First(rec.Ppt_1hr_m.ToString("0.00000000"), 11) + "," +
                            First(rec.SnowDepth_m.ToString("0.00000000"), 11) + "\r\n"
                        );
                    }
                    else if (model_type == "Hydro8")
                    {
                        sw.Write(
                            dateStr + "," +
                            timeStr + "," +
                            First(rec.Tair_2m_C.ToString("0.00000000"), 11) + "," +
                            First(rec.Tdew_2m_C.ToString("0.00000000"), 11) + "," +
                            First(rec.Radiation_Net_Wpm2.ToString("0.00000000"), 11) + "," +
                            First(rec.Wspd_mps.ToString("0.00000000"), 11) + "," +
                            First(rec.Ppt_1hr_m.ToString("0.00000000"), 11) + "," +
                            First(rec.SnowDepth_m.ToString("0.00000000"), 11) + "\r\n"
                        );
                    }
                }
            }
        }

        private void CreateEvapDatCSV(List<SurfaceWeather> SurfaceWeather_List_final, string evFile)
        {
            if (SurfaceWeather_List_final == null || SurfaceWeather_List_final.Count == 0)
                throw new InvalidOperationException("SurfaceWeather_List_final is empty; cannot create Evaporation.csv.");

            using (StreamWriter sw = File.CreateText(evFile))
            {
                // Header
                sw.WriteLine("YYYYMMDD,HH:MM:SS," +
                             "PotentialEvapotranspiration_TreeCover_mph(m/h)," +
                             "PotentialEvaporation_WaterOnGround_mph(m/h)," +
                             "PotentialEvaporation_WaterOnTree_mph(m/h)," +
                             "PotentialSublimation_SnowOnGround_mph(m/h)," +
                             "PotentialSublimation_SnowOnTree_mph(m/h)");

                foreach (var rec in SurfaceWeather_List_final)
                {
                    string dateStr = rec.TimeStamp.ToString("yyyyMMdd");
                    string timeStr = rec.TimeStamp.ToString("HH':'mm':'ss");

                    sw.Write(
                        dateStr + "," +
                        timeStr + "," +
                        First(rec.PtTrMh.ToString("0.00000000"), 11) + "," +   // pET
                        First(rec.PeGrMh.ToString("0.00000000"), 11) + "," +   // pE (water on ground)
                        First(rec.PeTrMh.ToString("0.00000000"), 11) + "," +   // pETree (water on tree)
                        First(rec.PeSnGrMh.ToString("0.00000000"), 11) + "," +   // PESnow (snow on ground)
                        First(rec.PeSnTrMh.ToString("0.00000000"), 11) + "\r\n"  // PeTreeSnow (snow on tree)
                    );
                }
            }
        }
        private void CreateSolarRadDatCSV(List<SurfaceWeather> SurfaceWeather_List_final, string srFile)
        {
            if (SurfaceWeather_List_final == null || SurfaceWeather_List_final.Count == 0)
                throw new InvalidOperationException("SurfaceWeather_List_final is empty; cannot create Radiation.csv.");

            using (StreamWriter sw = File.CreateText(srFile))
            {
                sw.WriteLine("YYYYMMDD,HH:MM:SS," +
                             "Radiation_Shortwave_Direct_Wpm2(W/m^2)," +
                             "Radiation_Shortwave_Diffuse_Wpm2(W/m^2)," +
                             "Radiation_Longwave_Downwelling_Wpm2(W/m^2)," +
                             "Radiation_Longwave_Upwelling_Wpm2(W/m^2)," +
                             "Latitude_rad(Radian)," +
                             "HourAngle_rad(Radian)," +
                             "DeclinationAngle_rad(Radian)");

                foreach (var rec in SurfaceWeather_List_final)
                {
                    string dateStr = rec.TimeStamp.ToString("yyyyMMdd");
                    string timeStr = rec.TimeStamp.ToString("HH':'mm':'ss");

                    sw.Write(
                        dateStr + "," +
                        timeStr + "," +
                        First(rec.Radiation_Shortwave_Direct_Wpm2.ToString("0.00000"), 7) + "," +
                        First(rec.Radiation_Shortwave_Diffuse_Wpm2.ToString("0.00000"), 7) + "," +
                        First(rec.Radiation_Longwave_Downwelling_Wpm2.ToString("0.00000"), 7) + "," +
                        First(rec.Radiation_Longwave_Upwelling_Wpm2.ToString("0.00000"), 7) + "," +
                        First(rec.LatRad.ToString("0.00000"), 7) + "," +
                        First(rec.HourAngleRad.ToString("0.00000"), 7) + "," +
                        First(rec.DecAngleRad.ToString("0.00000"), 7) + "\r\n"
                    );
                }
            }
        }
    }
}

