using Dapper;
using SolarPower.Helper;
using SolarPower.Models;
using SolarPower.Models.PowerStation;
using SolarPower.Repository.Interface;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;

namespace SolarPower.Repository.Implement
{
    public class OverviewRepository : RepositoryBase<Overview>, IOverviewRepository
    {
        public OverviewRepository(IDatabaseHelper databaseHelper) : base(databaseHelper)
        {
            tableName = "power_station";
        }

        public async Task<List<int>> GetAllCityIdAsync()
        {
            List<int> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $"SELECT Id FROM city";

                    result = (await conn.QueryAsync<int>(sql)).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<Overview> GetOverviewByPowerStationIds(List<int> powerStationIds)
        {
            Overview result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT
                                    SUM(ps.Today_kwh) AS Today_kwh,
                                    SUM(ps.Total_kwh) AS Total_kwh,
                                    AVG(ps.Today_irradiance) AS today_irradiance,
                                    AVG(ps.avg_irradiance) AS avg_irradiance,
                                    AVG(ps.today_PR) AS today_PR,
                                    AVG(ps.avg_PR) AS avg_PR,
                                    AVG(ps.today_kwhkwp) AS today_kwhkwp,
                                    AVG(ps.avg_kwhkwp) AS avg_kwhkwp,
                                    SUM(ps.today_money) AS today_money,
                                    SUM(ps.total_money) AS total_money,
                                    SUM(ps.today_carbon) AS today_carbon,
                                    SUM(ps.total_carbon) AS total_carbon
                                    FROM power_station ps
                                    WHERE ps.Id IN @PowerStationIds
                                ";

                    result = await conn.QueryFirstOrDefaultAsync<Overview>(sql, new { PowerStationIds = powerStationIds });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }

        }

        public async Task<List<CapacityDataTable>> GetCapacityDataTableByPowerStationIds(List<int> powerStationIds)
        {
            List<CapacityDataTable> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT 
                                    ps.CityId,
                                    c.Name AS CityName,
                                    COUNT(*) AS SubPowerStationCount,
                                    SUM(ps.GeneratingCapacity) AS SubTotalCapacity
                                    FROM power_station ps
                                    LEFT JOIN city c ON ps.CityId = c.Id
                                    WHERE ps.Id IN @PowerStationIds
                                    GROUP BY ps.CityId
                                ";

                    result = (await conn.QueryAsync<CapacityDataTable>(sql, new { PowerStationIds = powerStationIds })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<List<PowerStation>> GetListPowerStationByPowerStationIds(List<int> powerStationIds)
        {
            List<PowerStation> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT * FROM power_station ps WHERE ps.Id IN @PowerStationIds
                                ";

                    result = (await conn.QueryAsync<PowerStation>(sql, new { PowerStationIds = powerStationIds })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<List<PowerStation>> GetSolarByCity(MyUser User, UseStatusCityGetPowerStation post)
        {

            using IDbConnection conn = _databaseHelper.GetConnection();
            List<PowerStation> powerstation = new List<PowerStation>();
            conn.Open();
            var trans = conn.BeginTransaction();
            try
            {
                var ids = "";
                var KWH = "";
                var PR = "";
                if (post.KwhOrder == 0)
                {
                    KWH = " ORDER BY Today_kwh DESC";
                }
                else
                {
                    KWH = " ORDER BY Today_kwh";
                }

                if (post.PrOrder == 0)
                {
                    PR = ",today_PR DESC";
                }
                else
                {
                    PR = ",today_PR";
                }



                foreach (var id in post.Cityid)
                {
                    ids = ids + id + ",";
                }
                if (ids.Length != 0)
                {
                    ids = ids.Substring(0, ids.Length - 1);
                }
                if (User.Role.Layer == 0 || User.Role.Layer == 1)
                {
                    var sql = "SELECT * FROM power_station WHERE CityId IN @IDs AND HealthStatus IN @Status" + KWH + PR;
                    powerstation = (await conn.QueryAsync<PowerStation>(sql, new { IDs = post.Cityid, Status = post.Status })).ToList();
                    trans.Commit();
                }
                else if (User.Role.Layer == 2)
                {
                    var sql = "SELECT * FROM power_station WHERE CityId IN @IDs AND CompanyId=@CompanyId AND HealthStatus IN @Status" + KWH + PR;
                    powerstation = (await conn.QueryAsync<PowerStation>(sql, new { IDs = post.Cityid, CompanyId = User.CompanyId, Status = post.Status })).ToList();
                    trans.Commit();
                }
                else
                {
                    var sql = "SELECT power_station.* FROM power_station LEFT JOIN power_station_operation_personnel ON power_station.Id = power_station_operation_personnel.PowerStationId WHERE CityId IN @IDs AND Userid = @UserId AND HealthStatus IN @Status" + KWH + PR;
                    powerstation = (await conn.QueryAsync<PowerStation>(sql, new { IDs = post.Cityid, UserId = User.Id, Status = post.Status })).ToList();
                    trans.Commit();
                }
            }
            catch (Exception exception)
            {
                trans.Rollback();
                throw exception;
            }
            finally
            {
                conn.Close();
            }
            return powerstation;
        }

        public async Task<List<PowerIrradiance>> GetListPowerIrradianceTodayByPowerStationId(int powerStationId, string nowDay)
        {
            List<PowerIrradiance> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql_power = @$"SELECT DATE_FORMAT(ps.timestamp,'%H %p') AS Label, ps.KWH AS PowerData, pyr.Irradiance AS IrradianceData
                            FROM power_station_history_hour ps 
                            LEFT JOIN sensor_history_hour pyr ON ps.PowerStationId = pyr.PowerStationId AND DATE_FORMAT(ps.timestamp, '%Y-%m-%d %H') = DATE_FORMAT(pyr.timestamp, '%Y-%m-%d %H')
                            WHERE ps.PowerStationId = @PowerStationId
                            AND DATE_FORMAT(ps.timestamp, '%Y-%m-%d') = @NowDay";

                    result = (await conn.QueryAsync<PowerIrradiance>(sql_power, new { PowerStationId = powerStationId, NowDay = nowDay })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }
        public async Task<List<PowerIrradiance>> GetListPowerIrradiance7dayByPowerStationId(int powerStationId, string nowDay)
        {
            List<PowerIrradiance> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var startDay = Convert.ToDateTime(nowDay).AddDays(-7).ToString("yyyy-MM-dd");

                    var sql_power = @$"SELECT DATE_FORMAT(ps.timestamp, '%Y-%m-%d') AS Label, ps.TODAYKWH AS PowerData, pyr.Irradiance AS IrradianceData
                            FROM power_station_history_day ps 
                            LEFT JOIN sensor_history_day pyr ON ps.PowerStationId = pyr.PowerStationId AND DATE_FORMAT(ps.timestamp, '%Y-%m-%d') =  DATE_FORMAT(pyr.timestamp, '%Y-%m-%d')
                            WHERE ps.PowerStationId = @PowerStationId
                            AND DATE_FORMAT(ps.timestamp, '%Y-%m-%d') BETWEEN @StartDay AND @NowDay";

                    result = (await conn.QueryAsync<PowerIrradiance>(sql_power, new { PowerStationId = powerStationId, StartDay = startDay, NowDay = nowDay })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }
        public async Task<List<PowerIrradiance>> GetListPowerIrradianceMonthByPowerStationId(int powerStationId, string nowDay)
        {
            List<PowerIrradiance> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var startDay = Convert.ToDateTime(nowDay).ToString("yyyy-MM-01");

                    var sql_power = @$"SELECT DATE_FORMAT(ps.timestamp, '%Y-%m-%d') AS Label, ps.TODAYKWH AS PowerData, pyr.Irradiance AS IrradianceData
                            FROM power_station_history_day ps 
                            LEFT JOIN sensor_history_day pyr ON ps.PowerStationId = pyr.PowerStationId AND DATE_FORMAT(ps.timestamp, '%Y-%m-%d') = DATE_FORMAT(pyr.timestamp, '%Y-%m-%d')
                            WHERE ps.PowerStationId = @PowerStationId
                            AND DATE_FORMAT(ps.timestamp, '%Y-%m-%d') BETWEEN @StartDay AND @NowDay";

                    result = (await conn.QueryAsync<PowerIrradiance>(sql_power, new { PowerStationId = powerStationId, StartDay = startDay, NowDay = nowDay })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<List<PowerIrradiance>> GetListPowerIrradianceYearByPowerStationId(int powerStationId, string nowDay)
        {
            List<PowerIrradiance> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var startyear = Convert.ToDateTime(nowDay).ToString("yyyy");

                    var sql_power = @$"SELECT DATE_FORMAT(ps.timestamp, '%Y-%m') AS Label, ps.MONTHKWH AS PowerData, pyr.Irradiance AS IrradianceData
                            FROM power_station_history_month ps 
                            LEFT JOIN sensor_history_month pyr ON ps.PowerStationId = pyr.PowerStationId AND DATE_FORMAT(ps.timestamp, '%Y-%m') = DATE_FORMAT(pyr.timestamp, '%Y-%m')
                            WHERE ps.PowerStationId = @PowerStationId
                            AND DATE_FORMAT(ps.timestamp, '%Y') = @Year";

                    result = (await conn.QueryAsync<PowerIrradiance>(sql_power, new { PowerStationId = powerStationId, Year = startyear })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<List<CheckBox>> GetInvertCheckBoxByPowerStationId(int powerStationId, string db_name)
        {
            List<CheckBox> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT i.Id AS Value, i.InverterName AS Name FROM {db_name}.inverter i
                                LEFT JOIN {db_name}.controller c ON i.ControllerId = c.Id AND c.Deleted = 0
                                WHERE i.Deleted = 0 AND c.PowerStationId = @PowerStationId";

                    result = (await conn.QueryAsync<CheckBox>(sql, new { PowerStationId = powerStationId })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<List<InverterHistory>> GetListInverterByPowerStationIdAndDate(int powerStationId, string dateTime)
        {
            List<InverterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    //var startDateTime = dateTime + " 05:00";
                    //var endDataTime = dateTime + " 19:00";

                    //var sql = @$"SELECT * FROM inverter_history_15min WHERE PowerStationId = @PowerStationId AND DATE_FORMAT(TIMESTAMP, '%Y-%m-%d %H:%i') BETWEEN @StartDateTime AND @EndDateTime";
                    var sql = @$"SELECT * FROM inverter_history_15min WHERE PowerStationId = @PowerStationId AND DATE_FORMAT(TIMESTAMP, '%Y-%m-%d') = @DateTime";

                    result = (await conn.QueryAsync<InverterHistory>(sql, new { PowerStationId = powerStationId, DateTime = dateTime })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<List<ExceptionDataTable>> GetExceptionTable(ExceptionSent post)
        {


            List<ExceptionDataTable> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    DateTime start;
                    DateTime end;
                    var sql = @$"select pr.FormId as FormId, pr.Id as ErrorID, a.id, site_id, `timestamp`, FROM_UNIXTIME((`timestamp` / 1000), '%Y-%m-%d %H:%i:%s') dev_time ,  a.sourceState err_status, FROM_UNIXTIME( (a.normalTime / 1000), '%Y-%m-%d %H:%i:%s') normalTime,
                                    a.alarmClass, b.alarmClass as alarmClassName,ps.Name as PowerStationName,
                                    errDevice,  err_valueKind,  errValue,  FROM_UNIXTIME( (a.lastUpdate / 1000), '%Y-%m-%d %H:%i:%s')  lastUpdate, 
                                    case when c.errMsg_tw is null then d.errMsg_tw else c.errMsg_tw  end errMsg
                                    from err_main a 
                                    join alarmorion_orionalarmclass b on a.alarmclass = b.id 
                                    left join ref_err_device c on trim(b.alarmClass) = c.deviceType 
                                    left join ref_err_inv d on lower(b.alarmClass) = d.deviceType 
                                    and case when lower(b.alarmClass) = 'inverter' and err_valuekind = 'e' then errvalue else '' end = d.errCode
                                    left join power_station ps on ps.Code = site_id 
                                    left join operation_record pr on pr.ErrorCode = a.id
                                    WHERE a.sourceState = @Status AND ps.Id = @PowerStationId";


                    if (!string.IsNullOrEmpty(post.Range))
                    {
                        post.StartTime = post.Range.Split('-')[0];
                        post.EndTime = post.Range.Split('-')[1];
                        start = Convert.ToDateTime(post.StartTime);
                        end = Convert.ToDateTime(post.EndTime);
                        var startime = (Int64)(start.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
                        var endtime = (Int64)(end.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
                        sql += @$" AND `timestamp` BETWEEN {startime*1000} AND {endtime*1000}";
                    }

                    result = (await conn.QueryAsync<ExceptionDataTable>(sql,
                            new
                            {
                                PowerStationId = post.Id,
                                Status = post.Status,
                            })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<List<InverterHistory>> GetListInverterDayByPowerStationId(int powerStationId, string day)
        {
            List<InverterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql_power = @$"SELECT DATE_FORMAT(inv.TIMESTAMP, '%H %p') AS TIMESTAMP,
                                        inv.INVERTERID,
                                        inv.KWH
                                        FROM inverter_history_hour inv
                                        WHERE inv.PowerStationId = @PowerStationId
                                        AND DATE_FORMAT(inv.timestamp, '%Y-%m-%d') = @Day";

                    result = (await conn.QueryAsync<InverterHistory>(sql_power, new { PowerStationId = powerStationId, Day = day })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<List<InverterHistory>> GetListInverterMonthByPowerStationId(int powerStationId, string month)
        {
            List<InverterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql_power = @$"SELECT DATE_FORMAT(inv.TIMESTAMP, '%Y-%m-%d') AS TIMESTAMP,
                                        inv.INVERTERID,
                                        inv.KWH
                                        FROM inverter_history_day inv
                                        WHERE inv.PowerStationId = @PowerStationId
                                        AND DATE_FORMAT(inv.timestamp, '%Y-%m') = @Month";

                    result = (await conn.QueryAsync<InverterHistory>(sql_power, new { PowerStationId = powerStationId, Month = month })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<List<InverterHistory>> GetListInverterQuaryerlyByPowerStationId(int powerStationId, string startMonth, string endMonth)
        {
            List<InverterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql_power = @$"SELECT DATE_FORMAT(inv.TIMESTAMP, '%Y-%m') AS TIMESTAMP,
                                        inv.INVERTERID,
                                        inv.KWH
                                        FROM inverter_history_month inv
                                        WHERE inv.PowerStationId = @PowerStationId
                                        AND DATE_FORMAT(inv.timestamp, '%Y-%m') BETWEEN @StartMonth AND @EndMonth";

                    result = (await conn.QueryAsync<InverterHistory>(sql_power, new { PowerStationId = powerStationId, StartMonth = startMonth, EndMonth = endMonth })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<List<InverterHistory>> GetListInverterYearByPowerStationId(int powerStationId, string year)
        {
            List<InverterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql_power = @$"SELECT DATE_FORMAT(inv.TIMESTAMP, '%Y-%m') AS TIMESTAMP,
                                        inv.INVERTERID,
                                        inv.KWH
                                        FROM inverter_history_month inv
                                        WHERE inv.PowerStationId = @PowerStationId
                                        AND DATE_FORMAT(inv.timestamp, '%Y') = @Year";

                    result = (await conn.QueryAsync<InverterHistory>(sql_power, new { PowerStationId = powerStationId, Year = year })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<List<HistoryTable>> GethistoryTable(HistorySent post)
        {
            List<HistoryTable> result;

            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                var kwh = "";
                var usedb = "";
                var pyrdb = "";
                var timeGroup = "";
                var range = "";
                var range2 = "";
                switch (post.GroupType)
                {
                    case 0:
                        kwh = "C.KWH";
                        usedb = "power_station_history_hour";
                        pyrdb = "sensor_history_hour";
                        timeGroup = "%Y-%m-%d %H:%M:%S";
                        range = $" WHERE DATE_FORMAT(V.TIMESTAMP,'%Y-%m-%d')  = '{post.HistoryRange}'";
                        range2 = $" AND DATE_FORMAT(C.TIMESTAMP,'%Y-%m-%d')  = '{post.HistoryRange}'";

                        break;
                    case 1:
                        kwh = "C.TODAYKWH";
                        usedb = "power_station_history_day";
                        pyrdb = "sensor_history_day";
                        timeGroup = "%Y-%m-%d";
                        range = $" WHERE DATE_FORMAT(V.TIMESTAMP,'%Y-%m')  = '{post.HistoryRange}'";
                        //range2 = $" DATE_FORMAT(C.TIMESTAMP,'%Y-%m')  = '{post.HistoryRange}'";

                        break;
                    case 2:
                        kwh = "C.MONTHKWH";
                        usedb = "power_station_history_month";
                        pyrdb = "sensor_history_month";
                        timeGroup = "%Y-%m";
                        range = $" WHERE DATE_FORMAT(V.TIMESTAMP,'%Y')  = '{post.HistoryRange}'";
                        //range2 = $" DATE_FORMAT(C.TIMESTAMP,'%Y')  = '{post.HistoryRange}'";
                        break;
                    case 3:
                        kwh = "C.TOTALKWH";
                        usedb = "power_station_history_month";
                        pyrdb = "sensor_history_month";
                        timeGroup = "%Y-%m";
                        range = "";
                        break;
                }

                try
                {
                    var sql = @$"SELECT *, SOLARHOUR-PSValue AS DiffSOLARHOUR
                                    FROM
                                    (
	                                    SELECT B.*, IFNULL(A.SOLARHOUR,0) AS PSValue
	                                    FROM 
	                                    (	
		                                    SELECT DENSE_RANK() OVER(ORDER BY C.TIMESTAMP) AS ROWID
			                                    , (DENSE_RANK() OVER(ORDER BY C.TIMESTAMP)) - 1 AS PreROWID,
			                                    C.TIMESTAMP,{kwh} AS KWH,C.SOLARHOUR,C.PR,P.Irradiance,P.Temperature AS Temp 
			                                    FROM {usedb} C 
	                                        LEFT JOIN {pyrdb} P ON DATE_FORMAT(P.TIMESTAMP,'{timeGroup}') = DATE_FORMAT(C.TIMESTAMP,'{timeGroup}') 
                                            WHERE C.PowerStationId = {post.PowerstationId}{range2} GROUP BY C.TIMESTAMP ORDER BY C.TIMESTAMP
	                                    ) A
	                                    RIGHT OUTER JOIN 
	                                    (
		                                    SELECT DENSE_RANK() OVER(ORDER BY C.TIMESTAMP) AS ROWID
			                                    , (DENSE_RANK() OVER(ORDER BY C.TIMESTAMP)) - 1 AS PreROWID,
			                                    C.TIMESTAMP,{kwh} AS KWH,C.SOLARHOUR,C.PR,P.Irradiance,P.Temperature AS Temp 
			                                    FROM {usedb} C 
	                                        LEFT JOIN {pyrdb} P ON DATE_FORMAT(P.TIMESTAMP,'{timeGroup}') = DATE_FORMAT(C.TIMESTAMP,'{timeGroup}') 
                                            WHERE C.PowerStationId = {post.PowerstationId}{range2} GROUP BY C.TIMESTAMP ORDER BY C.TIMESTAMP
	                                    ) B
		                                    ON A.ROWID = B.PreROWID
                                    ) V {range}" ;
                    result = (await conn.QueryAsync<HistoryTable>(sql)).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }
    }
}
