using Dapper;
using SolarPower.Helper;
using SolarPower.Models.PowerStation;
using SolarPower.Models.User;
using SolarPower.Repository.Interface;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.Json;
using SolarPower.Models;
using SolarPower.Models.Role;
using SolarPower.Models.Company;
using SolarPower.Models.SensorType;
using MySql.Data.MySqlClient;

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

        public List<MyCity> GetMyCities(MyUser myUser, byte showEnable)
        {
            var results = new List<MyCity>();

            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var show_enable_str = " AND ps.Status = 1";

                    if (showEnable != 1)
                    {
                        show_enable_str = "";
                    }

                    var sql = @"SELECT c.Id AS CityId, c.Name AS CityName, COUNT(*) AS Amount
                                FROM power_station ps 
                                LEFT JOIN city c ON ps.CityId = c.Id";

                    if (myUser.Role.Layer == (int)RoleLayerEnum.CompanyAdmin)
                    {   //公司管理員
                        sql += $@" WHERE ps.Deleted = 0 {show_enable_str} AND ps.CompanyId = @CompanyId";
                    }
                    else if (myUser.Role.Layer == (int)RoleLayerEnum.PlatformUser || myUser.Role.Layer == (int)RoleLayerEnum.CompanyUser)
                    {
                        sql += $@" LEFT JOIN power_station_operation_personnel op ON ps.Id = op.PowerStationId
                                            WHERE ps.Deleted = 0 {show_enable_str} AND op.Deleted = 0 AND op.UserId = @UserId ";
                    }
                    else
                    {
                        sql += $@" WHERE ps.Deleted = 0 {show_enable_str}";
                    }

                    sql += @" GROUP BY c.Id ORDER BY c.Priority";

                    results = conn.Query<MyCity>(sql, new { CompanyId = myUser.CompanyId, UserId = myUser.Id }).ToList();

                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return results;
            }
        }

        public List<PowerStation> GetMyPowerStationList(MyUser myUser, byte showEnable, List<int> cityIds, List<string> wheres = null, Dictionary<string, object> where_entities = null, List<string> orderBy = null)
        {
            var results = new List<PowerStation>();

            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var show_enable_str = " AND ps.Status = 1";

                    if (showEnable != 1)
                    {
                        show_enable_str = "";
                    }
                    var now = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");

                    var sql = $@"SELECT ps.*, c.Name AS CityName, wf.Wx
                                FROM power_station ps 
                                LEFT JOIN city c ON ps.CityId = c.Id
                                LEFT JOIN (SELECT * FROM (
                                            SELECT MAX(w.Id) AS aa FROM weather_forecast w 
                                            WHERE '{now}' BETWEEN w.StartTime AND w.EndTime
                                            GROUP BY w.LocationName
                                            ) A
                                            LEFT JOIN weather_forecast B ON A.aa = B.Id) wf ON c.Name = wf.LocationName";
                    //var sql = $@"SELECT ps.*, c.Name AS CityName, wf.Wx
                    //            FROM power_station ps 
                    //            LEFT JOIN city c ON ps.CityId = c.Id
                    //            LEFT JOIN (
                    //                           SELECT  LocationName, Wx  FROM weather_forecast w 
                    //                           WHERE '{now}' BETWEEN w.StartTime AND w.EndTime
                    //                           GROUP BY w.LocationName
                    //                      ) wf ON c.Name = wf.LocationName";

                    if (myUser.Role.Layer == (int)RoleLayerEnum.CompanyAdmin)
                    {   //公司管理員
                        sql += $@" WHERE ps.Deleted = 0 {show_enable_str} AND ps.CompanyId = @CompanyId";
                    }
                    else if (myUser.Role.Layer == (int)RoleLayerEnum.PlatformUser || myUser.Role.Layer == (int)RoleLayerEnum.CompanyUser)
                    {
                        sql += $@" LEFT JOIN power_station_operation_personnel op ON ps.Id = op.PowerStationId
                                            WHERE ps.Deleted = 0 {show_enable_str} AND op.Deleted = 0 AND op.UserId = @UserId ";
                    }
                    else
                    {
                        sql += $@" WHERE ps.Deleted = 0 {show_enable_str}";
                    }

                    if (cityIds != null)
                    {
                        sql += @" AND c.Id IN @CityIds";
                    }

                    if (wheres != null && wheres.Count > 0)
                    {
                        var temp_where = "";
                        temp_where = string.Join(" AND ", wheres);
                        sql += " AND " + string.Join(" AND ", wheres);
                    }

                    if (orderBy != null && orderBy.Count > 0)
                    {
                        var temp_order = "";
                        temp_order = string.Join(" , ", orderBy);
                        sql += $" ORDER BY {temp_order}";
                    }
                    else
                    {
                        sql += $" ORDER BY c.Priority";
                    }

                    Dictionary<string, object> pairs = new Dictionary<string, object>();
                    pairs.Add("CompanyId", myUser.CompanyId);
                    pairs.Add("UserId", myUser.Id);
                    pairs.Add("CityIds", cityIds);

                    if (where_entities != null && where_entities.Count() > 0)
                    {
                        foreach (var entity in where_entities)
                        {
                            pairs.Add(entity.Key, entity.Value);
                        }
                    }

                    results = conn.Query<PowerStation>(sql, pairs).ToList();

                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return results;
            }
        }

        //public List<MyPowerStationSummary> GetMyPowerStationSummary(MyUser myUser, string filter = "")
        //{
        //    List<MyPowerStationSummary> results = new List<MyPowerStationSummary>();

        //    using (IDbConnection conn = this._databaseHelper.GetConnection())
        //    {
        //        try
        //        {
        //            var sql = @"SELECT ps.Id, ps.CityId, c.Name AS CityName, ps.Name
        //                        FROM power_station ps 
        //                        LEFT JOIN city c ON ps.CityId = c.Id";

        //            if (myUser.Role.Layer == (int)RoleLayerEnum.CompanyAdmin)
        //            {   //公司管理員
        //                sql += @" WHERE ps.Deleted = 0 AND ps.CompanyId = @CompanyId";
        //            }
        //            else if (myUser.Role.Layer == (int)RoleLayerEnum.PlatformUser || myUser.Role.Layer == (int)RoleLayerEnum.CompanyUser)
        //            {
        //                sql += @" LEFT JOIN power_station_operation_personnel op ON ps.Id = op.PowerStationId
        //                            WHERE ps.Deleted = 0 AND op.Deleted = 0 AND op.UserId = @UserId ";
        //            }
        //            else
        //            {
        //                sql += @" WHERE ps.Deleted = 0";
        //            }

        //            if (!string.IsNullOrEmpty(filter))
        //            {
        //                sql += @" AND ps.Name LIKE CONCAT('%', @Filter, '%')";
        //            }

        //            sql += " ORDER BY c.Priority";

        //            var myPowerStationInfos = conn.Query<MyPowerStationInfo>(sql, new { CompanyId = myUser.CompanyId, UserId = myUser.Id, Filter = filter }).ToList();

        //            var myPowerStationInfos_group = myPowerStationInfos.GroupBy(x => x.CityId);

        //            foreach (var myPowerStationInfo in myPowerStationInfos_group)
        //            {
        //                MyPowerStationSummary myPowerStationSummary = new MyPowerStationSummary();
        //                myPowerStationSummary.CityName = myPowerStationInfo.First().CityName;
        //                myPowerStationSummary.Amount = myPowerStationInfo.Count();
        //                myPowerStationSummary.MyPowerStations = new List<MyPowerStation>();
        //                foreach (var info in myPowerStationInfo)
        //                {
        //                    MyPowerStation myPowerStation = new MyPowerStation();
        //                    myPowerStation.PowerStationId = info.Id;
        //                    myPowerStation.PowerStationName = info.Name;

        //                    myPowerStationSummary.MyPowerStations.Add(myPowerStation);
        //                }

        //                results.Add(myPowerStationSummary);
        //            }

        //        }
        //        catch (Exception exception)
        //        {
        //            throw exception;
        //        }
        //        return results;
        //    }
        //}

        /// <summary>
        /// 查詢縣市列表
        /// </summary>
        /// <returns></returns>
        public async Task<List<CitySelectItemList>> GetCitySelectOptionListAsync()
        {
            List<CitySelectItemList> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $"SELECT Id AS Value, Name AS Text FROM city";

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

        /// <summary>
        /// 查詢地區列表
        /// </summary>
        /// <param name="cityId"></param>
        /// <returns></returns>
        public async Task<List<AreaSelectItemList>> GetAreaSelectOptionListAsync(int cityId)
        {
            List<AreaSelectItemList> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $"SELECT Id AS Value, Name AS Text FROM area WHERE CityId = @CityId";

                    result = (await conn.QueryAsync<AreaSelectItemList>(sql, new { CityId = cityId })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        /// <summary>
        /// 取得下拉式公司選單，須為Deleted: 0
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public async Task<List<CompanySelectItemList>> GetCompanySelectOptionListAsync(int companyId = 0)
        {
            List<CompanySelectItemList> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $"SELECT Id AS Value, CONCAT(Name, '/', SiteDB) AS Text FROM company WHERE Deleted = 0";

                    if (companyId > 0)
                    {
                        sql += " AND Id = @SelectedCompanyId";
                    }

                    result = (await conn.QueryAsync<CompanySelectItemList>(sql, new { SelectedCompanyId = companyId })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        /// <summary>
        /// 透過編號取得，縣市資訊
        /// </summary>
        /// <param name="cityId"></param>
        /// <returns></returns>
        public async Task<City> GetOneCityByIdAsync(int cityId)
        {
            City result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT * FROM city WHERE Id=@Id";

                    result = await conn.QueryFirstOrDefaultAsync<City>(sql, new { Id = cityId });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        /// <summary>
        /// 透過編號取得，地區資訊
        /// </summary>
        /// <param name="areaId"></param>
        /// <returns></returns>
        public async Task<Area> GetOneAreaByIdAsync(int areaId)
        {
            Area result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT * FROM area WHERE Id=@Id";

                    result = await conn.QueryFirstOrDefaultAsync<Area>(sql, new { Id = areaId });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        /// <summary>
        /// 透過地區編號，取得縣市地區代碼
        /// </summary>
        /// <param name="areaId"></param>
        /// <returns></returns>
        public async Task<Zipcode> GetCityAreaZipcodeAsync(int areaId)
        {
            Zipcode result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT a.ZipCode AS Area, c.ZipCode AS City FROM area a
                                    LEFT JOIN city c ON a.cityId = c.Id
                                    WHERE a.Id = @AreaId";

                    result = await conn.QueryFirstOrDefaultAsync<Zipcode>(sql, new { AreaId = areaId });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        /// <summary>
        /// 透過縣市地區編號，取得該縣市地區最後的流水號
        /// </summary>
        /// <param name="cityId"></param>
        /// <param name="areaId"></param>
        /// <returns></returns>
        public async Task<string> GetLastSerialNumberByCityAreaIdAsync(int cityId, int areaId)
        {
            string result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT SerialNumber FROM {tableName}
                                    WHERE CityId = @CityId && AreaId = @AreaId ORDER BY SerialNumber DESC";

                    result = await conn.QueryFirstOrDefaultAsync<string>(sql, new { CityId = cityId, AreaId = areaId });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public override async Task<List<PowerStation>> GetAllAsync()
        {
            List<PowerStation> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $"SELECT * FROM {tableName} WHERE Deleted = 0 AND Status = 1";

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

        public async Task<List<PowerStation>> GetAllNoStatusAsync()
        {
            List<PowerStation> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $"SELECT * FROM {tableName} WHERE Deleted = 0";

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

        /// <summary>
        /// 透過電站編號，取得單一電站資訊(覆寫)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public override async Task<PowerStation> GetOneAsync(int id)
        {
            //base.GetOneAsync(id);

            PowerStation result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    var sql = @$"SELECT ps.*, c.Name AS CityName, a.Name AS AreaName, u.Name AS CreatorName FROM {tableName} ps
                                LEFT JOIN user u ON ps.CreatedBy = u.Id
                                LEFT JOIN city c ON ps.CityId = c.Id
                                LEFT JOIN area a ON ps.AreaId = a.Id
                                WHERE ps.Deleted = 0 AND ps.Id = @Id";

                    result = await conn.QueryFirstOrDefaultAsync<PowerStation>(sql, new { Id = id });

                    //if (result != null)
                    //{

                    //    var db_name = result.SiteDB;

                    //    var sql_operation_personnel = @$"SELECT UserId FROM power_station_operation_personnel op WHERE Deleted = 0 AND op.PowerStationId = @PowerStationId";
                    //    result.OperationPersonnelIds = (await conn.QueryAsync<int>(sql_operation_personnel, new { PowerStationId = result.Id })).ToList();
                    //    var sql_land_building = @$"SELECT lb.*, u.Name AS CreatorName FROM {db_name}.land_building lb
                    //                                LEFT JOIN user u ON lb.CreatedBy = u.Id
                    //                                WHERE lb.Deleted = 0 AND PowerStationId = @PowerStationId";
                    //    result.LandBuildings = (await conn.QueryAsync<LandBuilding>(sql_land_building, new { PowerStationId = result.Id })).ToList();
                    //}
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public  async Task<PowerStation> GetStationExtraInfo(int id)
        {
            //base.GetOneAsync(id);

            PowerStation result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    var sql = @$"SELECT ps.*, c.Name AS CityName, a.Name AS AreaName, u.Name AS CreatorName FROM {tableName} ps
                                LEFT JOIN user u ON ps.CreatedBy = u.Id
                                LEFT JOIN city c ON ps.CityId = c.Id
                                LEFT JOIN area a ON ps.AreaId = a.Id
                                WHERE ps.Deleted = 0 AND ps.Id = @Id";

                    result = await conn.QueryFirstOrDefaultAsync<PowerStation>(sql, new { Id = id });

                    if (result != null)
                    {

                        var db_name = result.SiteDB;

                        var sql_operation_personnel = @$"SELECT UserId FROM power_station_operation_personnel op WHERE Deleted = 0 AND op.PowerStationId = @PowerStationId";
                        result.OperationPersonnelIds = (await conn.QueryAsync<int>(sql_operation_personnel, new { PowerStationId = result.Id })).ToList();
                        var sql_land_building = @$"SELECT lb.*, u.Name AS CreatorName FROM {db_name}.land_building lb
                                                    LEFT JOIN user u ON lb.CreatedBy = u.Id
                                                    WHERE lb.Deleted = 0 AND PowerStationId = @PowerStationId";
                        result.LandBuildings = (await conn.QueryAsync<LandBuilding>(sql_land_building, new { PowerStationId = result.Id })).ToList();
                    }
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }


        /// <summary>
        /// 新增電站資料至 主、子資料庫
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="properties"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<int> AddOnePowerStationAsync(PowerStation entity, List<string> properties, string db_name)
        {
            int id; int sub_count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        //新增資料 至主資料庫
                        string sql = GenerateInsertQuery(properties);

                        sql += "SELECT LAST_INSERT_ID();";

                        id = (await conn.QueryAsync<int>(sql, entity, trans)).Single();

                        //新增資料 至子資料庫
                        properties.Add("Id");
                        entity.Id = id;

                        string sub_sql = GenerateInsertQueryWithCustomDBNameAndTable(properties, db_name, tableName);
                        sub_count = await conn.ExecuteAsync(sub_sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return id;
            }
        }

        /// <summary>
        /// 修改主、子資料庫電站基本資訊
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="properties"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task UpdatePowerStationInfo(UpdatePowerStationInfo entity, List<string> properties, string db_name)
        {

            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        //修改主資料庫
                        var sql = GenerateUpdateQuery(properties);
                        await conn.ExecuteAsync(sql, entity, trans);

                        //修改子資料庫
                        var sub_sql = GenerateUpdateQueryWithCustomDBNameAndTable(properties, db_name, tableName);
                        await conn.ExecuteAsync(sub_sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        /// <summary>
        /// 修改主、子資料庫能源局與台電資訊
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="properties"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task UpdateBoETPCInfo(UpdateBoETPCInfo entity, List<string> properties, string db_name)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        //修改主資料庫
                        var sql = GenerateUpdateQuery(properties);
                        await conn.ExecuteAsync(sql, entity, trans);

                        //修改子資料庫
                        var sub_sql = GenerateUpdateQueryWithCustomDBNameAndTable(properties, db_name, tableName);
                        await conn.ExecuteAsync(sub_sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        /// <summary>
        /// 透過電站編號，取得所有土地房屋資訊
        /// </summary>
        /// <param name="id"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<List<LandBuilding>> GetAllLandBuildingInfoByPowerStationId(int id, string db_name)
        {
            List<LandBuilding> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT lb.*, u.Name AS CreatorName FROM {db_name}.land_building lb
                                LEFT JOIN user u ON lb.CreatedBy = u.Id
                                WHERE lb.Deleted = 0 AND PowerStationId = @PowerStationId";

                    result = (await conn.QueryAsync<LandBuilding>(sql, new { PowerStationId = id }, commandTimeout: 600)).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        /// <summary>
        /// 取得 土地房屋資訊
        /// </summary>
        /// <param name="id"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<LandBuilding> GetOneLandBuildingInfo(int id, string db_name)
        {
            LandBuilding result;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    var sql = @$"SELECT * FROM {db_name}.land_building WHERE Deleted = 0 AND Id = @Id";

                    result = await conn.QueryFirstOrDefaultAsync<LandBuilding>(sql, new { Id = id });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }

                return result;
            }
        }

        /// <summary>
        /// 新增 土地房屋資訊
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="properties"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<int> AddOneLandBuildingInfo(LandBuilding entity, List<string> properties, string db_name)
        {
            int id;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    string sql = GenerateInsertQueryWithCustomDBNameAndTable(properties, db_name, "land_building");

                    sql += "SELECT LAST_INSERT_ID();";

                    id = (await conn.QueryAsync<int>(sql, entity)).Single();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }

                return id;
            }
        }

        /// <summary>
        /// 更新 土地房屋資訊
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="properties"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task UpdateLandBuildingInfo(UpdateLandBuilding entity, List<string> properties, string db_name)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = GenerateUpdateQueryWithCustomDBNameAndTable(properties, db_name, "land_building");

                        await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        /// <summary>
        /// 軟刪除土地房屋資訊
        /// </summary>
        /// <param name="id"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task DeleteOneLandBuildingInfo(int id, string db_name)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = $"UPDATE {db_name}.land_building SET Deleted = 1 WHERE Id = @Id";

                        await conn.ExecuteAsync(sql, new { Id = id }, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        /// <summary>
        /// 新增運維
        /// </summary>
        /// <param name="operation"></param>
        /// <param name="properties"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<int> AddOperation(OperationInfo operation, List<string> properties, string db_name)
        {
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                int count;
                conn.Open();
                try
                {
                    string sql = GenerateInsertQueryWithCustomDBNameAndTable(properties, db_name, "operation_firm");

                    count = await conn.ExecuteAsync(sql, operation);

                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }

                return count;
            }
        }

        /// <summary>
        /// 運維DataTable
        /// </summary>
        /// <param name="stationId"></param>
        /// <param name="stationId"></param>
        /// <returns></returns>
        public async Task<List<OperationTable>> OperationTable(int stationId, string db_name)
        {

            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                List<OperationTable> operation = new List<OperationTable>();
                conn.Open();
                try
                {
                    string sql = @$"SELECT 
                                    operation_firm.Name,
                                    operation_firm.PowerStationId,
                                    operation_firm.Id,
                                    operation_firm.ContactPerson,
                                    operation_firm.Phone,
                                    operation_firm.Email,
                                    user.Name AS CreatedName,
                                    operation_firm.CreatedAt,operation_firm.Type
                                    FROM {db_name}.operation_firm
                                    LEFT JOIN user ON operation_firm.CreatedBy = user.id 
                                    WHERE operation_firm.Deleted = 0 AND operation_firm.PowerStationId = @StationId";
                    operation = (await conn.QueryAsync<OperationTable>(sql, new { StationId = stationId })).ToList();

                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return operation;
            }
        }
        /// <summary>
        /// 選取單一運維
        /// </summary>
        /// <param name="id"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<OperationInfo> OneOperationInfo(int id, string db_name)
        {
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                OperationInfo operation;
                conn.Open();
                try
                {
                    string sql = @$"SELECT * FROM {db_name}.operation_firm WHERE Id = @Id";
                    operation = await conn.QueryFirstOrDefaultAsync<OperationInfo>(sql, new { Id = id });

                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return operation;
            }
        }

        /// <summary>
        /// 更新運維
        /// </summary>
        /// <param name="operation"></param>
        /// <param name="properties"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task UpdateOperation(OperationInfo operation, List<string> properties, string db_name)
        {
            using IDbConnection conn = _databaseHelper.GetConnection();
            conn.Open();
            var trans = conn.BeginTransaction();
            try
            {
                var sql = GenerateUpdateQueryWithCustomDBNameAndTable(properties, db_name, "operation_firm");
                await conn.ExecuteAsync(sql, operation, trans);
                trans.Commit();
            }
            catch (Exception exception)
            {
                trans.Rollback();
                throw exception;
            }
            finally
            {
                conn.Close();
            }
        }
        /// <summary>
        /// 裝置類型下拉選單
        /// </summary>
        /// <returns></returns>
        public async Task<List<UserSelectItemList>> DeviceType()
        {
            List<UserSelectItemList> result = new List<UserSelectItemList>();
            using IDbConnection conn = _databaseHelper.GetConnection();
            conn.Open();
            var trans = conn.BeginTransaction();
            try
            {
                var sql = @$"SELECT 
                                st.*,
                                std.SensorTypeId AS SensorTypeId, std.Deleted AS ItemDeleted, std.ItemName AS ItemName, std.ItemEName AS ItemEName
                            FROM sensor_type st
                            LEFT JOIN sensor_type_detail std ON st.Id = std.SensorTypeId AND std.Deleted = 0
                            WHERE st.Deleted = 0 ";

                var json3 = (await conn.QueryAsync<SensorTypeWithDetail>(sql)).ToList();
                foreach (SensorTypeWithDetail a in json3)
                {
                    string subName = "";
                    if (a.ItemName != null)
                    {
                        subName = " - " + a.ItemName;
                    }
                    UserSelectItemList KeyValue = new UserSelectItemList
                    {
                        Value = a.SensorEName,
                        Text = a.SensorName + subName
                    };
                    result.Add(KeyValue);
                }
                trans.Commit();
            }
            catch (Exception exception)
            {
                trans.Rollback();
                throw exception;
            }
            finally
            {
                conn.Close();
            }
            return result;
        }

        /// <summary>
        /// 新增裝置資料
        /// </summary>
        /// <param name="DeviceInfo"></param>
        /// <param name="properties"></param>
        /// <returns></returns>
        public async Task AddDevice(Device DeviceInfo, List<string> properties, string db_name)
        {
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                var trans = conn.BeginTransaction();
                try
                {
                    string getSensorTypeId = $@"SELECT id from sensor_type
                                                WHERE SensorEName = '{DeviceInfo.Type}' AND Deleted = 0";
                    DeviceInfo.SensorTypeId = await conn.QueryFirstOrDefaultAsync<int>(getSensorTypeId);
                    DeviceInfo.SensorTypeDetailId = DeviceInfo.SensorTypeId;

                    string sql = GenerateInsertQueryWithCustomDBNameAndTable(properties, db_name, "device");
                    await conn.ExecuteAsync(sql, DeviceInfo);
                    trans.Commit();
                }
                catch (Exception exception)
                {
                    trans.Rollback();
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
            }


        }
        /// <summary>
        /// 修改裝置資料
        /// </summary>
        /// <param name="DeviceInfo"></param>
        /// <param name="properties"></param>
        /// <returns></returns>
        public async Task UpdateDevice(Device DeviceInfo, List<string> properties, string db_name)
        {
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                var trans = conn.BeginTransaction();
                try
                {
                    string getSensorTypeId = $@"SELECT id from sensor_type
                                                WHERE SensorEName = '{DeviceInfo.Type}' AND Deleted = 0";
                    DeviceInfo.SensorTypeId = await conn.QueryFirstOrDefaultAsync<int>(getSensorTypeId);
                    DeviceInfo.SensorTypeDetailId = DeviceInfo.SensorTypeId;

                    var updateQuery = GenerateUpdateQueryWithCustomDBNameAndTable(properties, db_name, "device");
                    await conn.ExecuteAsync(updateQuery.ToString(), DeviceInfo, trans);
                    trans.Commit();
                }
                catch (Exception exception)
                {
                    trans.Rollback();
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
            }
        }
        /// <summary>
        /// 裝置dataTable
        /// </summary>
        /// <param name="stationId"></param>
        /// <returns></returns>
        public async Task<List<DeviceTable>> DeviceTable(int stationId, string db_name)
        {
            using IDbConnection conn = _databaseHelper.GetConnection();
            conn.Open();
            List<DeviceTable> Device = new List<DeviceTable>();
            try
            {
                string sql = @$"SELECT de.*, con.ControllerId AS ControllerName,ps.Code AS PowerStationName FROM {db_name}.device de 
                                LEFT JOIN {db_name}.controller con ON de.ControllerId = con.id  
                                LEFT JOIN {db_name}.power_station ps ON de.PowerStationId = ps.id
                                WHERE de.Deleted = 0 AND de.PowerStationId = @StationId ";
                Device = (await conn.QueryAsync<DeviceTable>(sql, new { StationId = stationId })).ToList();
            }
            catch (Exception exception)
            {
                throw exception;
            }
            finally
            {
                conn.Close();
            }
            return Device;
        }
        /// <summary>
        /// 取單一筆DeviceInfo
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<DeviceInfo> OneDeviceInfo(int id, string db_name)
        {
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                DeviceInfo Device;
                conn.Open();
                try
                {
                    string sql = @$"SELECT * FROM {db_name}.device WHERE Id = @Id";
                    Device = await conn.QueryFirstOrDefaultAsync<DeviceInfo>(sql, new { Id = id });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return Device;
            }
        }
        /// <summary>
        /// 新增 異常設定
        /// </summary>
        /// <param name="Exception"></param>
        /// <param name="properties"></param>
        /// <returns></returns>
        public async Task AddException(ExceptionModal Exception, List<string> properties, string db_name)
        {
            using IDbConnection conn = _databaseHelper.GetConnection();
            conn.Open();
            try
            {
                string sql = GenerateInsertQueryWithCustomDBNameAndTable(properties, db_name, "power_station_exception");

                await conn.ExecuteAsync(sql, Exception);

            }
            catch (Exception exception)
            {
                throw exception;
            }
            finally
            {
                conn.Close();
            }
        }

        /// <summary>
        /// 異常dataTable
        /// </summary>
        /// <param name="stationId"></param>
        /// <returns></returns>
        public async Task<List<ExceptionTable>> ExceptionTable(int stationId, string db_name)
        {
            using IDbConnection conn = _databaseHelper.GetConnection();
            conn.Open();
            List<ExceptionTable> Exception = new List<ExceptionTable>();
            try
            {
                string sql = @$"SELECT pe.Type,
                                pe.UpperLimit,
                                pe.LowerLimit,
                                api.ItemName AS TypeName,
                                pe.Alarm,ps.Code AS PowerStationCode ,
                                ps.Name AS PowerStationName,
                                pe.CreatedAt,
                                pe.Id
                                FROM {db_name}.power_station_exception pe 
                                LEFT JOIN {db_name}.power_station ps ON pe.PowerStationId = ps.Id 
                                LEFT JOIN apicall api ON api.Item = pe.Type and ps.Id = api.PowerStationId
                                WHERE pe.Deleted = 0 AND pe.PowerStationId = @StationId GROUP BY pe.Id";
                Exception = (await conn.QueryAsync<ExceptionTable>(sql, new { StationId = stationId })).ToList();
            }
            catch (Exception exception)
            {
                throw exception;
            }
            finally
            {
                conn.Close();
            }
            return Exception;
        }
        /// <summary>
        /// 取一筆異常設定
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<ExceptionModal> OneException(int id, string db_name)
        {
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                ExceptionModal Exception;
                conn.Open();
                try
                {
                    string sql = @$"SELECT * FROM {db_name}.power_station_exception WHERE Id = @Id";
                    Exception = await conn.QueryFirstOrDefaultAsync<ExceptionModal>(sql, new { Id = id });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return Exception;
            }
        }
        /// <summary>
        /// 更新異常設定
        /// </summary>
        /// <param name="Exception"></param>
        /// <param name="properties"></param>
        /// <returns></returns>
        public async Task UpdateException(ExceptionModal Exception, List<string> properties, string db_name)
        {
            using IDbConnection conn = _databaseHelper.GetConnection();
            conn.Open();
            var trans = conn.BeginTransaction();
            try
            {
                var updateQuery = GenerateUpdateQueryWithCustomDBNameAndTable(properties, db_name, "power_station_exception");
                await conn.ExecuteAsync(updateQuery.ToString(), Exception, trans);
                trans.Commit();
            }
            catch (Exception exception)
            {
                trans.Rollback();
                throw exception;
            }
            finally
            {
                conn.Close();
            }
        }
        public async Task<string> GetFinalSerialNumber(int PowerStationId, string Type, string db_name)
        {
            string Num;
            using IDbConnection conn = _databaseHelper.GetConnection();
            conn.Open();
            var trans = conn.BeginTransaction();
            try
            {
                var sql = $"SELECT SerialNumber FROM {db_name}.device WHERE PowerStationId = @PowerStationId AND Type = @Type ORDER BY SerialNumber DESC";
                Num = await conn.QueryFirstOrDefaultAsync<string>(sql, new { PowerStationId = PowerStationId, Type = Type });
                trans.Commit();
            }
            catch (Exception exception)
            {
                trans.Rollback();
                throw exception;
            }
            finally
            {
                conn.Close();
            }
            return Num;
        }

        /// <summary>
        /// 透過電站編號，取得該電站的運維人員編號
        /// </summary>
        /// <param name="powerStationId"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<List<int>> GetOperationPersonnelIdsByPowerStatioinId(int powerStationId)
        {
            List<int> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    var sql = @$"SELECT UserId FROM power_station_operation_personnel WHERE Deleted = 0 AND PowerStationId = @PowerStationId";

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

        /// <summary>
        /// 新增電站運維人員
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="properties"></param>
        /// <returns></returns>
        public async Task<int> AddOperationPersonnelAsync(List<PowerStationOperationPersonnel> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    string sql = GenerateInsertQueryWithCustomTable(properties, "power_station_operation_personnel");

                    count = await conn.ExecuteAsync(sql, entity);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }

                return count;
            }
        }

        /// <summary>
        /// 軟刪除電站運維人員
        /// </summary>
        /// <param name="operationPersonnels"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task DeleteOperationPersonnel(List<PowerStationOperationPersonnel> operationPersonnels)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = $"UPDATE power_station_operation_personnel SET Deleted = 1 WHERE PowerStationId = @PowerStationId AND UserId = @UserId";

                        await conn.ExecuteAsync(sql, operationPersonnels, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        /// <summary>
        /// 電站管理 新增電站圖片
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<int> AddPowerStationImageAsync(List<PowerStationImage> entity, List<string> properties, string db_name)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomDBNameAndTable(properties, db_name, "power_station_image");

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        /// <summary>
        /// 電站管理 取得所有電站圖片的資料
        /// </summary>
        /// <param name="powerStationId"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<List<PowerStationImage>> GetAllPowerStationImageAsync(int powerStationId, string db_name)
        {
            List<PowerStationImage> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $"SELECT * FROM {db_name}.power_station_image WHERE Deleted = 0 AND PowerStationId = @PowerStationId";

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

        /// <summary>
        /// 電站管理 取得單一電站圖片的資料
        /// </summary>
        /// <param name="id"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<PowerStationImage> GetOnePowerStationImageAsync(int id, string db_name)
        {
            PowerStationImage result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $"SELECT * FROM {db_name}.power_station_image WHERE Deleted = 0 AND Id = @Id";

                    result = await conn.QueryFirstOrDefaultAsync<PowerStationImage>(sql, new { Id = id });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        /// <summary>
        /// 軟刪除 單一電站圖片
        /// </summary>
        /// <param name="id"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task DeleteOnePowerStationImage(int id, string db_name)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = $"UPDATE {db_name}.power_station_image SET Deleted = 1 WHERE id = @Id";

                        await conn.ExecuteAsync(sql, new { Id = id }, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        /// <summary>
        /// 電站管理 取得主要卡片顯示圖
        /// </summary>
        /// <param name="powerStationId"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<PowerStationImage> GetMainDisplayAsync(int powerStationId, string db_name)
        {
            PowerStationImage result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $"SELECT * FROM {db_name}.power_station_image WHERE Deleted = 0 AND IsMainDisplay = 1 AND PowerStationId = @PowerStationId";

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

        /// <summary>
        /// 電站管理 更新上傳圖片
        /// </summary>
        /// <param name="image"></param>
        /// <param name="properties"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task UpdatePowerStationImage(UpdataPowerStationImage image, List<string> properties, string db_name)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = GenerateUpdateQueryWithCustomDBNameAndTable(properties, db_name, "power_station_image");

                        await conn.ExecuteAsync(sql, image, trans);


                        var sql_MainDispalyImg = string.Empty;
                        List<string> powerStationMainDispalyImg = new List<string>()
                        {
                            "Id",
                            "MainDisplay"
                        };

                        if (image.IsMainDisplay == 1)
                        {
                            //修改主資料庫
                            sql_MainDispalyImg = GenerateUpdateQuery(powerStationMainDispalyImg);
                            await conn.ExecuteAsync(sql_MainDispalyImg, new { Id = image.PowerStationId, MainDisplay = image.Image }, trans);

                            //修改子資料庫
                            sql_MainDispalyImg = GenerateUpdateQueryWithCustomDBNameAndTable(powerStationMainDispalyImg, db_name, "power_station");
                            await conn.ExecuteAsync(sql_MainDispalyImg, new { Id = image.PowerStationId, MainDisplay = image.Image }, trans);
                        }

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        /// <summary>
        /// 電站管理 新增單線圖
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="properties"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<int> AddPowerStationSingleLineAsync(List<PowerStationSingleLine> entity, List<string> properties, string db_name)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    string sql = GenerateInsertQueryWithCustomDBNameAndTable(properties, db_name, "power_station_single_line_diagram");

                    count = await conn.ExecuteAsync(sql, entity);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }

                return count;
            }
        }

        /// <summary>
        /// 電站管理 取得所有單線圖的資料
        /// </summary>
        /// <param name="powerStationId"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<List<PowerStationSingleLine>> GetAllPowerStationSingleLineAsync(int powerStationId, string db_name)
        {
            List<PowerStationSingleLine> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $"SELECT * FROM {db_name}.power_station_single_line_diagram WHERE Deleted = 0 AND PowerStationId = @PowerStationId";

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

        /// <summary>
        /// 電站管理 取得單一單線圖的資料
        /// </summary>
        /// <param name="id"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<PowerStationSingleLine> GetOnePowerStationSingleLineAsync(int id, string db_name)
        {
            PowerStationSingleLine result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $"SELECT * FROM {db_name}.power_station_single_line_diagram WHERE Deleted = 0 AND Id = @Id";

                    result = await conn.QueryFirstOrDefaultAsync<PowerStationSingleLine>(sql, new { Id = id });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        /// <summary>
        /// 軟刪除 單一單線圖
        /// </summary>
        /// <param name="id"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task DeleteOnePowerStationSingleLine(int id, string db_name)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = $"UPDATE {db_name}.power_station_single_line_diagram SET deleted = 1 WHERE id = @Id";

                        await conn.ExecuteAsync(sql, new { Id = id }, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }
        public async Task<List<SolarCityAmount>> GetSolarCitySummary(MyUser User)
        {
            using IDbConnection conn = _databaseHelper.GetConnection();
            List<SolarCityAmount> solaramount = new List<SolarCityAmount>();
            conn.Open();
            try
            {
                if (User.Role.Layer == 0 || User.Role.Layer == 1)
                {
                    var sql = "SELECT city.Id AS CityId, city.Name AS City,COUNT(*) AS Amount FROM power_station LEFT JOIN city ON power_station.CityId = city.Id WHERE Deleted = 0 GROUP BY power_station.CityId ORDER BY city.Id";
                    solaramount = (await conn.QueryAsync<SolarCityAmount>(sql)).ToList();
                }
                else if (User.Role.Layer == 2)
                {
                    var sql = "SELECT city.Id AS CityId, city.Name AS City,COUNT(*) AS Amount FROM power_station LEFT JOIN city ON power_station.CityId = city.Id WHERE CompanyId = @CompanyId and Deleted = 0 GROUP BY power_station.CityId ORDER BY power_station.CityId";
                    solaramount = (await conn.QueryAsync<SolarCityAmount>(sql, new { CompanyId = User.CompanyId })).ToList();
                }
                else
                {
                    var sql = "SELECT city.Id AS CityId, city.Name AS City,COUNT(*) AS Amount FROM power_station LEFT JOIN city ON power_station.CityId = city.Id LEFT JOIN power_station_operation_personnel ON power_station.Id = power_station_operation_personnel.PowerStationId WHERE UserId = @UserId and Deleted = 0 GROUP BY power_station.CityId ORDER BY power_station.CityId";
                    solaramount = (await conn.QueryAsync<SolarCityAmount>(sql, new { UserId = User.Id })).ToList();
                }
            }
            catch (Exception exception)
            {
                throw exception;
            }
            finally
            {
                conn.Close();
            }
            return solaramount;
        }
        public async Task<List<PowerStation>> GetSolarByCity(MyUser User, List<int> CityId)
        {
            using IDbConnection conn = _databaseHelper.GetConnection();
            List<PowerStation> powerstation = new List<PowerStation>();
            conn.Open();
            try
            {
                var ids = "";
                foreach (var id in 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 ps.* , c.Name AS CityName, a.Name AS AreaName
                                FROM power_station ps
                                LEFT JOIN city c ON ps.CityId = c.Id
                                LEFT JOIN area a ON ps.AreaId = a.Id
                                WHERE ps.CityId IN @IDs and ps.Deleted = 0";
                    powerstation = (await conn.QueryAsync<PowerStation>(sql, new { IDs = CityId })).ToList();
                }
                else if (User.Role.Layer == 2)
                {
                    var sql = @"SELECT ps.* , c.Name AS CityName, a.Name AS AreaName
                                FROM power_station ps
                                LEFT JOIN city c ON ps.CityId = c.Id
                                LEFT JOIN area a ON ps.AreaId = a.Id
                                WHERE ps.CityId IN @IDs
                                AND ps.CompanyId=@CompanyId and ps.Deleted = 0";
                    powerstation = (await conn.QueryAsync<PowerStation>(sql, new { IDs = CityId, CompanyId = User.CompanyId })).ToList();
                }
                else
                {
                    var sql = @"SELECT ps.* , c.Name AS CityName, a.Name AS AreaName
                                FROM power_station ps
                                LEFT JOIN city c ON ps.CityId = c.Id
                                LEFT JOIN area a ON ps.AreaId = a.Id
                                LEFT JOIN power_station_operation_personnel psop ON ps.Id = psop.PowerStationId
                                WHERE ps.CityId IN @IDs AND psop.Userid = @UserId and ps.Deleted = 0";
                    powerstation = (await conn.QueryAsync<PowerStation>(sql, new { IDs = CityId, UserId = User.Id })).ToList();
                }
            }
            catch (Exception exception)
            {
                throw exception;
            }
            finally
            {
                conn.Close();
            }
            return powerstation;
        }

        public async Task<List<OperationPersonnelSelectItemList>> GetOperationPersonnelSelectOptionListAsync(int powerStationId)
        {
            List<OperationPersonnelSelectItemList> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT u.Id AS Value, u.Name AS Text 
                                FROM power_station_operation_personnel op
                                LEFT JOIN user u ON op.UserId = u.Id
                                WHERE op.Deleted = 0 AND op.PowerStationId = @PowerStationId";

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

        public async Task<List<FirmlSelectItemList>> GetFimlSelectOptionListAsync(int powerStationId, string siteDB)
        {
            List<FirmlSelectItemList> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT aa.Id AS Value, aa.Name AS Text 
                                FROM {siteDB}.operation_firm aa
                                WHERE aa.Deleted = 0 AND aa.PowerStationId = @PowerStationId";

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

        /// <summary>
        /// 新增控制器
        /// </summary>
        /// <param name="deviceController"></param>
        /// <param name="properties"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task AddDeviceController(DeviceController deviceController, List<string> properties, string db_name)
        {
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                int count;
                conn.Open();
                try
                {
                    string sql = GenerateInsertQueryWithCustomDBNameAndTable(properties, db_name, "controller");

                    count = await conn.ExecuteAsync(sql, deviceController);

                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
            }
        }
        /// <summary>
        /// 控制器dataTable
        /// </summary>
        /// <param name="stationId"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<List<DeviceControllerTable>> DeviceControllerTable(int stationId, string db_name)
        {

            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                List<DeviceControllerTable> deviceControllerTable = new List<DeviceControllerTable>();
                conn.Open();
                try
                {
                    string sql = @$"SELECT 
                                    col.ControllerId,user.Name As CreatedName ,col.CreatedAt,col.Id
                                    FROM {db_name}.controller col
                                    LEFT JOIN user ON col.CreatedBy = user.id 
                                    WHERE col.Deleted = 0 AND col.PowerStationId = @StationId";
                    deviceControllerTable = (await conn.QueryAsync<DeviceControllerTable>(sql, new { StationId = stationId })).ToList();

                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return deviceControllerTable;
            }
        }
        /// <summary>
        /// 新增逆變器
        /// </summary>
        /// <param name="inverter"></param>
        /// <param name="properties"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task AddInverter(Inverter inverter, List<string> properties, string db_name)
        {
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                int count;
                conn.Open();
                try
                {
                    string sql = GenerateInsertQueryWithCustomDBNameAndTable(properties, db_name, "inverter");
                    count = await conn.ExecuteAsync(sql, inverter);

                    //string updateToInv_Status = @"DROP TABLE IF EXISTS solar_master.`inv_status`;
                    //        create table solar_master.inv_status
                    //        select * from solar_master.v_company_inv
                    //        where enabled = 1;
                    //        ALTER TABLE solar_master.`inv_status` ADD INDEX inv_status_index (`inverterid`);";

                    //count = await conn.ExecuteAsync(updateToInv_Status, inverter);

                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
            }
        }

        /// <summary>
        /// 在master.inv_status資料表中 新增逆變器
        /// </summary>
        /// <param name="inverter"></param>
        /// <param name="properties"></param>
        /// <returns></returns>
        public async Task AddMasterInverter(InverterForMaster inverter, List<string> properties)
        {
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                int count;
                conn.Open();
                try
                {
                    var sql = GenerateInsertQueryWithCustomTable(properties, "inv_status");
                    count = await conn.ExecuteAsync(sql, inverter);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
            }
        }

        /// <summary>
        /// 取得控制器所有id
        /// </summary>
        /// <param name="stationId"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<List<int>> GetAllDeviceControllerId(int stationId, string db_name)
        {
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                List<int> count;
                conn.Open();
                try
                {
                    string sql = $"SELECT id FROM {db_name}.controller WHERE PowerStationId = {stationId}";
                    count = (await conn.QueryAsync<int>(sql, commandTimeout: 600)).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return count;
            }
        }

        /// <summary>
        /// 透過電站Id，取得所有控制器編碼
        /// </summary>
        /// <param name="stationId"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<List<string>> GetAllDeviceControllerByPowerStationId(int stationId, string db_name)
        {
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                List<string> result;
                conn.Open();
                try
                {
                    string sql = $"SELECT ControllerId FROM {db_name}.controller WHERE PowerStationId = {stationId}";
                    result = (await conn.QueryAsync<string>(sql)).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        /// <summary>
        /// 逆變器DataTable
        /// </summary>
        /// <param name="controllerid"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<List<InverterTable>> InverterTable(List<int> controllerid, string db_name)
        {

            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                List<InverterTable> inverterTable = new List<InverterTable>();
                conn.Open();
                try
                {
                    string sql = @$"SELECT 
                                    inv.*, con.ControllerId AS ControllerName,user.Name As CreatedName,de.UID AS PyrheliometerName, invs.status AS InverterStatus
                                    FROM {db_name}.inverter inv
                                    LEFT JOIN {db_name}.controller con ON inv.ControllerId = con.id 
                                    LEFT JOIN user ON inv.CreatedBy = user.id 
                                    LEFT JOIN {db_name}.device de ON inv.Pyrheliometer = de.id     
                                    LEFT JOIN inv_status invs ON inv.InverterId = invs.InverterId
                                    WHERE inv.Deleted = 0 AND inv.ControllerId IN @Controllerid";
                    inverterTable = (await conn.QueryAsync<InverterTable>(sql, new { Controllerid = controllerid }, commandTimeout: 600)).ToList();

                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return inverterTable;
            }
        }

        /// <summary>
        /// 取單一逆變器
        /// </summary>
        /// <param name="id"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task<InverterTable> GetOneMasterInverter(int id, string db_name)
        {

            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                InverterTable inverter = new InverterTable();
                conn.Open();
                try
                {
                    string sql = $@"SELECT a.InverterId
                                    FROM solar_master.inv_status a join {db_name}.inverter b on a.inverterid = b.inverterid 
                                    WHERE a.Deleted = 0 AND b.Id = {id}";
                    inverter = (await conn.QueryFirstOrDefaultAsync<InverterTable>(sql, commandTimeout: 600));

                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return inverter;
            }
        }

        /// <summary>
        /// 其餘電站列表
        /// </summary>
        /// <returns></returns>
        public async Task<List<PowerstationOptionAndName>> GetPowerstationOptionAsync(string db_name, int stationId)
        {
            List<PowerstationOptionAndName> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT Id AS Value, Code AS Text ,Name  FROM {db_name}.power_station WHERE Deleted = 0 AND Id !={stationId} AND Status = 1";

                    result = (await conn.QueryAsync<PowerstationOptionAndName>(sql)).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }
        /// <summary>
        /// 電站日照計列表
        /// </summary>
        /// <returns></returns>
        public async Task<List<PowerstationOption>> GetPowerstationPyrheliometerAsync(string db_name, int stationId)
        {
            List<PowerstationOption> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT dd.Id AS Value, dd.UID AS Text FROM {db_name}.device dd WHERE dd.Deleted = 0 AND dd.PowerStationId = {stationId} AND dd.Type = 'PYR' 
                                UNION SELECT dd.Id AS Value, dd.UID AS Text FROM {db_name}.sharedevice sh LEFT JOIN {db_name}.device dd ON sh.DeviceId = dd.Id
                                WHERE dd.Deleted = 0 AND sh.PowerStationId = {stationId};";

                    result = (await conn.QueryAsync<PowerstationOption>(sql)).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }
        /// <summary>
        /// 設備編號下拉式選單
        /// </summary>
        /// <param name="db_name"></param>
        /// <param name="stationId"></param>
        /// <returns></returns>
        public async Task<List<PowerstationOptionAndName>> GetDeviceUIDListAsync(string db_name, int stationId)
        {
            List<PowerstationOptionAndName> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT Id AS Value, UID AS Text, Name FROM {db_name}.device WHERE Deleted = 0 AND PowerStationId ={stationId}";

                    result = (await conn.QueryAsync<PowerstationOptionAndName>(sql)).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }
        /// <summary>
        /// 新增共享設備
        /// </summary>
        /// <param name="sharedevice"></param>
        /// <param name="properties"></param>
        /// <param name="db_name"></param>
        /// <returns></returns>
        public async Task AddShareDevice(Sharedevice sharedevice, List<string> properties, string db_name)
        {
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    string sql = GenerateInsertQueryWithCustomDBNameAndTable(properties, db_name, "sharedevice");
                    await conn.ExecuteAsync(sql, sharedevice);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
            }
        }


        /// <summary>
        /// 共享裝置dataTable
        /// </summary>
        /// <param name="stationId"></param>
        /// <returns></returns>
        public async Task<List<DeviceTable>> shareDeviceTables(int stationId, string db_name)
        {
            using IDbConnection conn = _databaseHelper.GetConnection();
            conn.Open();
            List<DeviceTable> Device = new List<DeviceTable>();
            try
            {
                string sql = @$"SELECT de.*, con.ControllerId AS ControllerName,ps.Code AS PowerStationName, sh.Id FROM {db_name}.sharedevice sh
                                LEFT JOIN {db_name}.device de ON sh.DeviceId = de.Id
                                LEFT JOIN {db_name}.controller con ON de.ControllerId = con.id  
                                LEFT JOIN {db_name}.power_station ps ON de.PowerStationId = ps.id
                                WHERE de.Deleted = 0 AND sh.PowerStationId = @StationId ";
                Device = (await conn.QueryAsync<DeviceTable>(sql, new { StationId = stationId })).ToList();
            }
            catch (Exception exception)
            {
                throw exception;
            }
            finally
            {
                conn.Close();
            }
            return Device;
        }

        /// <summary>
        /// 取一筆各型態資料
        /// </summary>
        /// <typeparam name="A"></typeparam>
        /// <param name="where"></param>
        /// <param name="db_name"></param>
        /// <param name="table_name"></param>
        /// <returns></returns>
        public async Task<A> GetoneData<A>(string where, string db_name, string table_name)
        {
            A result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $"SELECT * FROM {db_name}.{table_name} WHERE {where}";

                    result = await conn.QueryFirstOrDefaultAsync<A>(sql, commandTimeout: 600);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<PowerStationHistory> GetPowerStationHistoryPerHour(string dateTime, string table_name)
        {
            PowerStationHistory result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"
                    SELECT 
                    DATE_FORMAT(FROM_UNIXTIME(timestamp / 1000), '%Y-%m-%d %H') AS TIMESTAMP,
                    SITEID,
                    SiteType,
                    KWH,
                    TodayKWh,
                    TotalKWH,
                    KWHKWP,
                    PR,
                    MP,
                    SolarHour
                    FROM {table_name} WHERE DATE_FORMAT(FROM_UNIXTIME(timestamp / 1000), '%Y-%m-%d %H') = @DateTime
                    ";

                    result = await conn.QueryFirstOrDefaultAsync<PowerStationHistory>(sql, new { DateTime = dateTime }, commandTimeout: 600);//加上時間
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<PowerStationHistory> GetPowerStationHistoryPerHourForPowerStation(string dateTime, string table_name)
        {
            PowerStationHistory result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"
                    SELECT  
                    DATE_FORMAT(FROM_UNIXTIME(timestamp / 1000), '%Y-%m-%d %H') AS TIMESTAMP,
                    SITEID, SiteType,  KWH,  TodayKWh, TotalKWH,
                    KWHKWP,  PR,   MP, SolarHour
                    FROM {table_name}
                    WHERE DATE_FORMAT(FROM_UNIXTIME(timestamp / 1000), '%Y-%m-%d') = @DateTime
                    AND kwh > 0
                    order by timestamp desc";

                    result = await conn.QueryFirstOrDefaultAsync<PowerStationHistory>(sql, new { DateTime = dateTime }, commandTimeout: 600);//加上時間
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<AvgPowerStationHistory> CalcAvgPowerStationHistory30day(string nowDay, string table_name)
        {
            AvgPowerStationHistory result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var startDay = Convert.ToDateTime(nowDay).AddDays(-30).ToString("yyyy-MM-dd");

                    var sql = $@"SELECT AVG(s.KWHKWP) AS AvgKWHKWP, AVG(s.PR) AS AvgPR
                                    FROM {table_name} s 
                                    WHERE DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/1000), '%Y-%m-%d %H') IN (
	                                    SELECT MAX(DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/1000), '%Y-%m-%d %H')) FROM {table_name} s 
	                                    WHERE DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/1000), '%Y-%m-%d') BETWEEN @StartDay AND @EndDay
	                                    GROUP BY DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/1000), '%Y-%m-%d')) 
                                ";

                    result = await conn.QueryFirstOrDefaultAsync<AvgPowerStationHistory>(sql, new { StartDay = startDay, EndDay = nowDay });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<int> AddPowerStationHistory(List<PowerStationHistory> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "power_station_history_hour");

                        count = await conn.ExecuteAsync(sql, entity, trans, commandTimeout: 600);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<int> UpdateList(List<PowerStation> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateUpdateQuery(properties);

                        count = await conn.ExecuteAsync(sql, entity, trans, commandTimeout: 600);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        /// <summary>
        /// 透過日期，取得最後一筆資料
        /// </summary>
        /// <param name="day"></param>
        /// <param name="table_name"></param>
        /// <returns></returns>
        public async Task<PowerStationHistoryDay> GetLastOnePowerStationHistoryByDay(string day, string table_name)
        {
            PowerStationHistoryDay result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT 
                                    DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/1000), '%Y-%m-%d %H') AS TIMESTAMP,
                                    s.SITEID,
                                    s.SITETYPE,
                                    s.TodayKWh,
                                    s.TotalKWH,
                                    s.KWHKWP,
                                    s.PR,
                                    s.MP,
                                    s.SolarHour
                                 FROM {table_name} s 
                                 WHERE DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/1000), '%Y-%m-%d') = @Day
                                 ORDER BY TIMESTAMP DESC
                                 LIMIT 1
                    ";

                    result = await conn.QueryFirstOrDefaultAsync<PowerStationHistoryDay>(sql, new { Day = day });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        /// <summary>
        /// 新增資料，至每日的電站歷史記錄
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="properties"></param>
        /// <returns></returns>
        public async Task<int> AddPowerStationHistoryDayList(List<PowerStationHistoryDay> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "power_station_history_day");

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<PowerStationHistoryMonth> GetOnePowerStationHistoryByPowerStationIdAndMonth(int powerStationId, string month)
        {
            PowerStationHistoryMonth result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT *
                                 FROM power_station_history_month s 
                                 WHERE PowerStationId = @PowerStationId
                                 AND DATE_FORMAT(s.TIMESTAMP, '%Y-%m')= @Month
                    ";

                    result = await conn.QueryFirstOrDefaultAsync<PowerStationHistoryMonth>(sql, new { PowerStationId = powerStationId, Month = month });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<PowerStationHistoryMonth> ClacPowerStationHistoryMonthDataByPowerStationId(int powerStationId, string month)
        {
            PowerStationHistoryMonth result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT 
                                    PowerStationId,
                                    DATE_FORMAT(s.TIMESTAMP, '%Y-%m') AS TIMESTAMP,
                                    s.SITEID,
                                    s.SITETYPE,
                                    SUM(s.TODAYKWH) AS MONTHKWH,
                                    MAX(s.TOTALKWH) AS TOTALKWH,
                                    AVG(s.KWHKWP) AS KWHKWP,
                                    AVG(s.PR) AS PR,
                                    AVG(s.MP) AS MP,
                                    SUM(s.SOLARHOUR)  AS SOLARHOUR
                                    FROM power_station_history_day s 
                                    WHERE DATE_FORMAT(s.TIMESTAMP, '%Y-%m') = @Month
                                    AND PowerStationId = @PowerStationId
                                    GROUP BY PowerStationId,DATE_FORMAT(s.TIMESTAMP, '%Y-%m')
                    ";

                    result = await conn.QueryFirstOrDefaultAsync<PowerStationHistoryMonth>(sql, new { PowerStationId = powerStationId, Month = month });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        /// <summary>
        /// 新增資料，至每月的電站歷史記錄
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="properties"></param>
        /// <returns></returns>
        public async Task<int> AddPowerStationHistoryMonthList(List<PowerStationHistoryMonth> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "power_station_history_month");

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<int> UpdatePowerStationHistoryMonthList(List<PowerStationHistoryMonth> entity)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = @"UPDATE power_station_history_month SET
                                        MonthKWh=@MonthKWh,
                                        TOTALKWH=@TOTALKWH,
                                        KWHKWP=@KWHKWP,
                                        PR=@PR,
                                        MP=@MP,
                                        SolarHour=@SolarHour,
                                        MONEY=@MONEY,
                                        TOTALMONEY=@TOTALMONEY,
                                        CARBON=@CARBON,
                                        TOTALCARBON=@TOTALCARBON
                                        WHERE PowerStationId = @PowerStationId
                                        AND TIMESTAMP LIKE CONCAT(@TIMESTAMP, '%')
";

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<int> UpdateInverter(Inverter entity, List<string> properties, string db_name)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateUpdateQueryWithCustomDBNameAndTable(properties, db_name, "inverter");

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        //string updateToInv_Status = @"DROP TABLE IF EXISTS solar_master.`inv_status`;
                        //    create table solar_master.inv_status
                        //    select * from solar_master.v_company_inv
                        //    where enabled = 1;
                        //    ALTER TABLE solar_master.`inv_status` ADD INDEX inv_status_index (`inverterid`);";

                        //await conn.ExecuteAsync(updateToInv_Status, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<int> UpdateMasterInverter(InverterForMaster entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = $@"UPDATE solar_master.inv_status a join {entity.DBName}.inverter b on a.inverterid = b.inverterid 
                                       	SET 
                                       		a.Enabled = {entity.Enabled},
                                       		a.Status = {entity.Status}
                                       WHERE b.id  = {entity.Id}";

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        /// <summary>
        /// 透過table_name、inverterId，軟刪除指定資料表的單一筆inverter
        /// </summary>
        /// <param name="inverterId"></param>
        /// <param name="table_name"></param>
        /// <returns></returns>
        public async Task DeleteOneMasterInverter(string inverterId, string table_name)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = $"UPDATE {table_name} SET Deleted = 1 WHERE InverterId = {inverterId}";

                        await conn.ExecuteAsync(sql, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }

                }
            }
        }

        public async Task<List<DeviceInfo>> GetListPyrheliometerByPowerStationId(int powerStationId, string db_name)
        {
            List<DeviceInfo> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT temp.*
                                FROM(
                                SELECT d.* 
                                    FROM {db_name}.device d 
                                    WHERE d.PowerStationId = @PowerStationId AND d.`Type` = 'TPY' AND d.Deleted = 0 AND d.Enabled = 1 AND d.Status != 0
                                 UNION
                                 SELECT d.* 
                                    FROM {db_name}.sharedevice sd 
                                    LEFT JOIN {db_name}.device d ON sd.DeviceId = d.Id
                                    WHERE sd.PowerStationId = @PowerStationId AND d.`Type` = 'TPY' AND d.Deleted = 0 AND d.Enabled = 1 AND d.Status != 0
                                ) temp
                                ORDER BY temp.ColName
                    ";

                    result = (await conn.QueryAsync<DeviceInfo>(sql, new { PowerStationId = powerStationId }, commandTimeout: 600)).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }
        //(有新增)
        public async Task<List<DeviceInfo>> GetListTempByPowerStationId(int powerStationId, string db_name)
        {
            List<DeviceInfo> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT temp.*
                                 FROM (SELECT * 
                                        FROM {db_name}.device d 
                                        WHERE d.PowerStationId = @PowerStationId AND d.`Type` = 'MTR' AND d.Deleted = 0 AND d.Enabled = 1 AND d.Status != 0
                                     UNION
                                     SELECT d.* 
                                        FROM {db_name}.sharedevice sd 
                                        LEFT JOIN {db_name}.device d ON sd.DeviceId = d.Id
                                        WHERE sd.PowerStationId = @PowerStationId AND d.`Type` = 'MTR' AND d.Deleted = 0 AND d.Enabled = 1 AND d.Status != 0
                                 ) temp
                                 ORDER BY temp.ColName";

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

        public async Task<List<DeviceInfo>> GetDeviceListByPowerStationIdAndType(int powerStationId, string type, string db_name)
        {
            List<DeviceInfo> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT temp.*
                                 FROM (SELECT * 
                                        FROM {db_name}.device d 
                                        WHERE d.PowerStationId = @PowerStationId AND d.`Type` = '{type}' AND d.Deleted = 0 AND d.Enabled = 1 AND d.Status != 0
                                     UNION
                                     SELECT d.* 
                                        FROM {db_name}.sharedevice sd 
                                        LEFT JOIN {db_name}.device d ON sd.DeviceId = d.Id
                                        WHERE sd.PowerStationId = @PowerStationId AND d.`Type` = '{type}' AND d.Deleted = 0 AND d.Enabled = 1 AND d.Status != 0
                                ) temp
                                ORDER BY temp.ColName";

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

        public async Task<PyrheliometerHistory> CalcSensorHistoryPerHour(string dateTime, List<DeviceInfo> deviceInfos, int type)
        {
            SensorTypeEnum SensorTypeEnum = (SensorTypeEnum)type;
            var typename = "";
            var calc = "";
            switch (SensorTypeEnum)
            {
                case SensorTypeEnum.PYR: //日照計
                    calc = "AVG";
                    typename = "Irradiance";
                    break;
                case SensorTypeEnum.MTR: //模組溫度計
                    calc = "AVG";
                    typename = "Temperature";
                    break;
                case SensorTypeEnum.ETR: //環境溫度計
                    calc = "AVG";
                    typename = "EnvTemperature";
                    break;
                case SensorTypeEnum.EMM: //環境濕度計
                    calc = "AVG";
                    typename = "Humidity";
                    break;
                case SensorTypeEnum.VAN: //風速計
                    calc = "AVG";
                    typename = "Vane";
                    break;
                case SensorTypeEnum.FOM: //落塵計
                    calc = "AVG";
                    typename = "Dust";
                    break;
                case SensorTypeEnum.WIN: //風向計
                    calc = "AVG";
                    typename = "WingDirection";
                    break;
                case SensorTypeEnum.TPY: //累計日照量
                    calc = "MAX";
                    typename = "IrrDay";
                    break;
            }

            PyrheliometerHistory result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    List<string> sql_per_device = new List<string>();

                    foreach (var device in deviceInfos)
                    {
                        var str = @$"SELECT DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/ 1000), '%Y-%m-%d %H') AS TIMESTAMP, s.SITEID, 
                                            CASE WHEN AVG(CASE WHEN s.{device.ColName} != 0 THEN s.{device.ColName} END) IS NOT NULL 
                                                 THEN AVG(CASE WHEN s.{device.ColName} != 0 THEN s.{device.ColName} END)
                                                 ELSE 0 END AS SENSOR
                                    FROM {device.DBName}.{device.TableName} s 
                                    WHERE DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/ 1000), '%Y-%m-%d %H') = @DateTime
                                    GROUP BY DATE_FORMAT(FROM_UNIXTIME(s.TIMESTAMP/ 1000), '%Y-%m-%d %H')";

                        sql_per_device.Add(str);
                    }

                    var sql = @$"SELECT a.TIMESTAMP, {calc}(a.SENSOR) AS {typename} FROM(" + string.Join(" UNION ", sql_per_device) + @") a GROUP BY `TIMESTAMP`";

                    result = await conn.QueryFirstOrDefaultAsync<PyrheliometerHistory>(sql, new { DateTime = dateTime }, commandTimeout: 600);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<int> AddSensorHistoryHour(List<PyrheliometerHistory> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "sensor_history_hour");

                        count = await conn.ExecuteAsync(sql, entity, trans, commandTimeout: 600);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }
        //(有新增)
        public async Task<int> AddTempHistory(List<PyrheliometerHistory> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateUpdateQueryWithCustomTableAndWHERE(properties, "sensor_history_hour", "PowerStationId = @PowerStationId AND TIMESTAMP = @Timestamp");

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<AvgPyrheliometerHistory> CalcAvgPyrheliometerHistory30day(string nowDay, int powerStationId)
        {
            AvgPyrheliometerHistory result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var startDay = Convert.ToDateTime(nowDay).AddDays(-30).ToString("yyyy-MM-dd");

                    //var sql = $@"SELECT AVG(p.Irradiance) AS AvgIrradiance
                    //                FROM sensor_history_hour p
                    //                WHERE DATE_FORMAT(p.TIMESTAMP, '%Y-%m-%d') BETWEEN @StartDay AND @EndDay
                    //                AND p.Irradiance != 0
                    //                AND PowerStationId = @PowerStationId
                    //                GROUP BY DATE_FORMAT(p.TIMESTAMP, '%Y-%m-%d')
                    //            ";

                    var sql = $@"SELECT AVG(p.irrDay) AS AvgIrradiance
                                    FROM sensor_history_day p
                                    WHERE DATE_FORMAT(p.TIMESTAMP, '%Y-%m-%d') BETWEEN @StartDay AND @EndDay
                                    AND p.Irradiance != 0
                                    AND PowerStationId = @PowerStationId
                                    GROUP BY DATE_FORMAT(p.TIMESTAMP, '%Y-%m')
                                ";

                    result = await conn.QueryFirstOrDefaultAsync<AvgPyrheliometerHistory>(sql, new { StartDay = startDay, EndDay = nowDay, PowerStationId = powerStationId });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<PyrheliometerHistory> CalcPyrheliometerHistoryDayDataByPowerStationId(string nowDay, int powerStationId)
        {
            PyrheliometerHistory result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    //var sql = $@"SELECT 
                    //                PowerStationId,
                    //                DATE_FORMAT(p.TIMESTAMP, '%Y-%m-%d') AS TIMESTAMP,
                    //                AVG(p.Irradiance) AS Irradiance,
                    //                AVG(p.Temperature) AS Temperature,
                    //                AVG(p.EnvTemperature) AS EnvTemperature,
                    //                AVG(p.Humidity) AS Humidity,
                    //                AVG(p.Vane) AS Vane,
                    //                AVG(p.Dust) AS Dust
                    //                FROM sensor_history_hour p
                    //                WHERE DATE_FORMAT(p.TIMESTAMP, '%Y-%m-%d') = @NowDay
                    //                AND PowerStationId = @PowerStationId
                    //                GROUP BY DATE_FORMAT(p.TIMESTAMP, '%Y-%m-%d')
                    //            ";

                    //TODO
                    var sql = $@" select a.powerstationID, a.reportdate, ifnull(b.Irradiance, 0) irrAvg, a.Temperature, a.envTemperature, a.humidity, a.Vane, a.Dust from 
	                                (
			                                select powerStationID , concat(DATE_FORMAT(`TIMESTAMP`,'%Y-%m-%d'), ' 00:00') reportdate, round(avg(Temperature), 6) Temperature, 
                                                    envTemperature, humidity, Vane, Dust
			                                from  solar_master.sensor_history_hour
			                                where PowerStationId = @PowerStationId and DATE_FORMAT(`TIMESTAMP`,'%Y-%m-%d') = @NowDay
			                                group by DATE_FORMAT(`TIMESTAMP`,'%Y-%m-%d') 
	                                ) a left join 
	                                ( -- 日照計
			                                select concat(DATE_FORMAT(`TIMESTAMP`,'%Y-%m-%d'), ' 00:00')  reportdate, round(avg(Irradiance), 2) Irradiance
			                                from   solar_master.sensor_history_hour
			                                where PowerStationId = @PowerStationId 
                                                  and DATE_FORMAT(`TIMESTAMP`,'%Y-%m-%d') = @NowDay and Irradiance <> 0 #需要過濾 0 的數值 
			                                group by DATE_FORMAT(`TIMESTAMP`,'%Y-%m-%d') 
	                                )b on a.reportdate = b.reportdate";

                    result = await conn.QueryFirstOrDefaultAsync<PyrheliometerHistory>(sql, new { NowDay = nowDay, PowerStationId = powerStationId });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<int> AddPyrheliometerHistoryDayList(List<PyrheliometerHistory> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "sensor_history_day");

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<PyrheliometerHistory> CalcPyrheliometerHistoryMonthDataByPowerStationId(string month, int powerStationId)
        {
            PyrheliometerHistory result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT 
                                    PowerStationId,
                                    DATE_FORMAT(p.TIMESTAMP, '%Y-%m') AS TIMESTAMP,
                                    AVG(p.Irradiance) AS Irradiance,
                                    AVG(p.Temperature) AS Temperature,
                                    AVG(p.EnvTemperature) AS EnvTemperature,
                                    AVG(p.Humidity) AS Humidity,
                                    AVG(p.Vane) AS Vane,
                                    AVG(p.Dust) AS Dust
                                    FROM sensor_history_hour p
                                    WHERE DATE_FORMAT(p.TIMESTAMP, '%Y-%m') = @Month
                                    AND PowerStationId = @PowerStationId
                                    GROUP BY DATE_FORMAT(p.TIMESTAMP, '%Y-%m')
                                ";

                    result = await conn.QueryFirstOrDefaultAsync<PyrheliometerHistory>(sql, new { Month = month, PowerStationId = powerStationId });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<PyrheliometerHistory> GetOnePyrheliometerHistoryByMonth(string month, int powerStationId)
        {
            PyrheliometerHistory result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT * FROM sensor_history_month WHERE DATE_FORMAT(TIMESTAMP, '%Y-%m') = @Month AND PowerStationId = @PowerStationId";

                    result = await conn.QueryFirstOrDefaultAsync<PyrheliometerHistory>(sql, new { Month = month, PowerStationId = powerStationId });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<int> AddPyrheliometerHistoryMonthList(List<PyrheliometerHistory> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "sensor_history_month");

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<int> UpdatePyrheliometerHistoryMonthList(List<PyrheliometerHistory> entity)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = @"UPDATE sensor_history_month SET
                                        Irradiance=@Irradiance,
                                        Temperature=@Temperature
                                        WHERE PowerStationId = @PowerStationId
                                        AND TIMESTAMP LIKE CONCAT(@TIMESTAMP, '%')
                                        ";

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<List<InverterHistory>> CalcInverterHisyort15minData(string dateTime, string db_name, string table_name, List<string> inverterIds)
        {
            List<InverterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var stratDateTime = Convert.ToDateTime(dateTime + ":00").AddMinutes(-15).ToString("yyyy-MM-dd HH:mm");

                    var sql = $@"SELECT 
                                    s.TIMESTAMP,
                                    s.INVERTERID,
                                    s.KWH,
                                    s.TODAYKWH,
                                    i.Capacity,
                                    s.KWH/(i.Capacity/4) AS KWHKWP
                                   FROM (SELECT 
                                                MAX(FROM_UNIXTIME(sub_inv.TIMESTAMP/1000, '%Y-%m-%d %H:%i')) AS TIMESTAMP,
                                                sub_inv.INVERTERID,
                                                SUM(sub_inv.WH)/1000 AS KWH,
                                                MAX(sub_inv.TODAYKWH) AS TODAYKWH
                                                FROM {table_name} sub_inv
                                                WHERE FROM_UNIXTIME(sub_inv.TIMESTAMP/1000, '%Y-%m-%d %H:%i') BETWEEN @StartDateTime AND @EndDateTime
                                                AND sub_inv.INVERTERID IN @InverterIds
                                                GROUP BY sub_inv.INVERTERID) s
                                   /*LEFT JOIN (
                                                SELECT MAX(FROM_UNIXTIME(sub_inv.TIMESTAMP/1000, '%Y-%m-%d %H:%i')) AS TIMESTAMP,
                                                    sub_inv.INVERTERID,
                                                    SUM(sub_inv.WH)/1000 AS KWH
                                                    FROM {table_name} sub_inv 
                                                    WHERE FROM_UNIXTIME(sub_inv.TIMESTAMP/1000, '%Y-%m-%d %H:%i') BETWEEN @StartDateTime AND @EndDateTime
                                                    AND sub_inv.INVERTERID IN @InverterIds
                                                    GROUP BY sub_inv.INVERTERID) a
                                    ON s.TIMESTAMP = a.TIMESTAMP AND s.INVERTERID = a. INVERTERID*/
                                    LEFT JOIN {db_name}.inverter i ON s.INVERTERID = REPLACE(i.InverterId, 's', '');";

                    result = (await conn.QueryAsync<InverterHistory>(sql, new { StartDateTime = stratDateTime, EndDateTime = dateTime, InverterIds = inverterIds }, commandTimeout: 300)).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<int> AddInverter15minHistory(List<InverterHistory> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "inverter_history_15min");

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
                return count;
            }
        }

        public async Task<List<InverterHistory>> CalcInverterHisyortHourData(string dateTime, string db_name, string table_name, List<string> inverterIds)
        {
            List<InverterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT 
                                    MAX(FROM_UNIXTIME(s.TIMESTAMP/1000, '%Y-%m-%d %H')) AS TIMESTAMP,
                                    s.INVERTERID,
                                    AVG(s.AC1V) AS AC1V,
                                    AVG(s.AC1A) AS AC1A,
                                    SUM(s.AC1W) AS AC1W,
                                    AVG(s.AC1F) AS AC1F,
                                    SUM(s.AC1WH) AS AC1WH,
                                    AVG(s.AC2V) AS AC2V,
                                    AVG(s.AC2A) AS AC2A,
                                    SUM(s.AC2W) AS AC2W,
                                    AVG(s.AC2F) AS AC2F,
                                    SUM(s.AC2WH) AS AC2WH,
                                    AVG(s.AC3V) AS AC3V,
                                    AVG(s.AC3A) AS AC3A,
                                    SUM(s.AC3W) AS AC3W,
                                    AVG(s.AC3F) AS AC3F,
                                    SUM(s.AC3WH) AS AC3WH,
                                    AVG(s.DC1V) AS DC1V,
                                    AVG(s.DC1A) AS DC1A,
                                    SUM(s.DC1W) AS DC1W,
                                    SUM(s.DC1WH) AS DC1WH,
                                    AVG(s.DC2V) AS DC2V,
                                    AVG(s.DC2A) AS DC2A,
                                    SUM(s.DC2W) AS DC2W,
                                    SUM(s.DC2WH) AS DC2WH,
                                    AVG(s.DC3V) AS DC3V,
                                    AVG(s.DC3A) AS DC3A,
                                    AVG(s.DC3W) AS DC3W,
                                    AVG(s.DC3WH) AS DC3WH,
                                    AVG(s.DC4V) AS DC4V,
                                    AVG(s.DC4A) AS DC4A,
                                    SUM(s.DC4W) AS DC4W,
                                    SUM(s.DC4WH) AS DC4WH,
                                    AVG(s.DC5V) AS DC5V,
                                    AVG(s.DC5A) AS DC5A,
                                    SUM(s.DC5W) AS DC5W,
                                    SUM(s.DC5WH) AS DC5WH,
                                    inv_pr.PR AS PR,
                                    AVG(s.RA1) AS RA1,
                                    AVG(s.RA2) AS RA2,
                                    AVG(s.RA3) AS RA3,
                                    AVG(s.RA4) AS RA4,
                                    AVG(s.RA5) AS RA5,
                                    SUM(s.WH)/1000 AS KWH,
                                    MAX(s.TODAYKWH) AS TODAYKWH,
                                    MAX(s.TOTALKWH) AS TOTALKWH,
                                    i.Capacity,
                                    ((SUM(s.WH)/1000) / i.Capacity) AS KWHKWP
                                FROM {table_name} s
                                -- 取得該時間區間的KWH
                                /*LEFT JOIN (
	                                SELECT 
                                        FROM_UNIXTIME(inv.TIMESTAMP/1000, '%Y-%m-%d %H') AS TIMESTAMP,
                                        inv.INVERTERID,
                                        SUM(inv.WH)/1000 AS KWH  
	                                FROM  {table_name} inv 
	                                WHERE DATE_FORMAT(FROM_UNIXTIME(inv.TIMESTAMP/1000), '%Y-%m-%d %H') = @DateTime 
                                    AND inv.INVERTERID IN @InverterIds
	                                GROUP BY FROM_UNIXTIME(inv.TIMESTAMP/1000, '%Y-%m-%d %H'), inv.INVERTERID) a
                                ON FROM_UNIXTIME(s.TIMESTAMP/1000, '%Y-%m-%d %H') = a.TIMESTAMP AND s.INVERTERID = a. INVERTERID*/
                                -- 取得整點值PR
                                LEFT JOIN (
                                    SELECT
                                        inv.CrdTime AS TIMESTAMP,
                                        inv.INVERTERID,
                                        inv.PR
                                    FROM  {table_name} inv 
	                                WHERE left(inv.CrdTime, 16) = CONCAT(@DateTime, ':55')
                                    AND inv.INVERTERID IN @InverterIds
	                                GROUP BY left(inv.CrdTime, 13), inv.INVERTERID) inv_pr
                                ON left(s.CrdTime, 13) = inv_pr.TIMESTAMP AND s.INVERTERID = inv_pr. INVERTERID
                                -- 取得逆變器容量
                                LEFT JOIN {db_name}.inverter i ON s.INVERTERID = i.InverterId
                                WHERE left(s.CrdTime, 13) = @DateTime
                                AND s.INVERTERID IN @InverterIds
                                GROUP BY left(s.CrdTime, 13), s.INVERTERID
                                ";

                    result = (await conn.QueryAsync<InverterHistory>(sql, new { DateTime = dateTime, InverterIds = inverterIds }, commandTimeout: 600)).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<DeviceInfo> GetFirstPyrheliometerInfo(int powerStationId, string db_name)
        {
            DeviceInfo result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT d.* 
                                    FROM {db_name}.device d 
                                    LEFT JOIN {db_name}.controller c ON d.ControllerId = c.Id AND c.Deleted = 0
                                    WHERE d.Deleted = 0 AND d.Enabled = 1 AND d.`Status` != 0 AND d.`Type` = 'PYR'
                                    AND d.PowerStationId = @PowerStationId
                                    ORDER BY d.ColName";

                    result = await conn.QueryFirstAsync<DeviceInfo>(sql, new { PowerStationId = powerStationId }, commandTimeout: 600);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<double> GetFirstPyrheliometerValue(string dateTime, string db_name, string table_name, string col_name)
        {
            double result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT CASE WHEN AVG({col_name}) IS NULL THEN 0
                                             WHEN AVG({col_name}) IS NOT NULL THEN AVG({col_name})
                                        END
                                    FROM {db_name}.{table_name}
                                    WHERE {col_name} != 0
                                    AND FROM_UNIXTIME(TIMESTAMP/1000, '%Y-%m-%d %H') = @DateTime";

                    result = await conn.QueryFirstOrDefaultAsync<double>(sql, new { DateTime = dateTime }, commandTimeout: 600);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally { conn.Close(); }
                return result;
            }
        }

        public async Task<List<InverterHistory>> CalcInverterHistoryDayDataByPowerStationId(string nowDay, string db_name, int powerStationId)
        {
            List<InverterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT 
                                inv.PowerStationId,
                                DATE_FORMAT(inv.TIMESTAMP, '%Y-%m-%d') AS TIMESTAMP,
                                inv.INVERTERID,
                                AVG(inv.Irradiance) AS Irradiance,
                                AVG(inv.AC1V) AS AC1V,
                                AVG(inv.AC1A) AS AC1A,
                                AVG(inv.AC1W) AS AC1W,
                                AVG(inv.AC1F) AS AC1F,
                                AVG(inv.AC1WH) AS AC1WH,
                                AVG(inv.AC2V) AS AC2V,
                                AVG(inv.AC2A) AS AC2A,
                                AVG(inv.AC2W) AS AC2W,
                                AVG(inv.AC2F) AS AC2F,
                                AVG(inv.AC2WH) AS AC2WH,
                                AVG(inv.AC3V) AS AC3V,
                                AVG(inv.AC3A) AS AC3A,
                                AVG(inv.AC3W) AS AC3W,
                                AVG(inv.AC3F) AS AC3F,
                                AVG(inv.AC3WH) AS AC3WH,
                                AVG(inv.DC1V) AS DC1V,
                                AVG(inv.DC1A) AS DC1A,
                                AVG(inv.DC1W) AS DC1W,
                                AVG(inv.DC1WH) AS DC1WH,
                                AVG(inv.DC2V) AS DC2V,
                                AVG(inv.DC2A) AS DC2A,
                                AVG(inv.DC2W) AS DC2W,
                                AVG(inv.DC2WH) AS DC2WH,
                                AVG(inv.DC3V) AS DC3V,
                                AVG(inv.DC3A) AS DC3A,
                                AVG(inv.DC3W) AS DC3W,
                                AVG(inv.DC3WH) AS DC3WH,
                                AVG(inv.DC4V) AS DC4V,
                                AVG(inv.DC4A) AS DC4A,
                                AVG(inv.DC4W) AS DC4W,
                                AVG(inv.DC4WH) AS DC4WH,
                                AVG(inv.DC5V) AS DC5V,
                                AVG(inv.DC5A) AS DC5A,
                                AVG(inv.DC5W) AS DC5W,
                                AVG(inv.DC5WH) AS DC5WH,
                                MAX(inv.PR) AS PR,
                                AVG(inv.RA1) AS RA1,
                                AVG(inv.RA2) AS RA2,
                                AVG(inv.RA3) AS RA3,
                                AVG(inv.RA4) AS RA4,
                                AVG(inv.RA5) AS RA5,
                                SUM(inv.KWH) AS KWH,
                                MAX(inv.TODAYKWH) AS TODAYKWH,
                                MAX(inv.TOTALKWH) AS TOTALKWH,
                                SUM(inv.KWH) / i.Capacity AS KWHKWP
                                FROM inverter_history_hour inv 
                                LEFT JOIN {db_name}.inverter i ON CONCAT('s', inv.INVERTERID) = i.InverterId
                                WHERE DATE_FORMAT(inv.TIMESTAMP, '%Y-%m-%d') = @NowDay 
                                AND PowerStationId = @PowerStationId
                                GROUP BY DATE_FORMAT(inv.TIMESTAMP, '%Y-%m-%d'), inv.INVERTERID";

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

        public async Task<int> AddInverterHistoryDayList(List<InverterHistory> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "inverter_history_day");

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<List<InverterHistory>> GetInverterHistoryByPowerStationIdAndMonth(string month, int powerStationId)
        {
            List<InverterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT * FROM inverter_history_month WHERE DATE_FORMAT(TIMESTAMP, '%Y-%m') = @Month AND PowerStationId = @PowerStationId";
                    result = (await conn.QueryAsync<InverterHistory>(sql, new { Month = month, PowerStationId = powerStationId })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<List<InverterHistory>> CalcInverterHistoryMonthDataByPowerStationId(string month, string db_name, int powerStationId)
        {
            List<InverterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT 
                                inv.PowerStationId,
                                DATE_FORMAT(inv.TIMESTAMP, '%Y-%m') AS TIMESTAMP,
                                inv.INVERTERID,
                                AVG(inv.Irradiance) AS Irradiance,
                                AVG(inv.AC1V) AS AC1V,
                                AVG(inv.AC1A) AS AC1A,
                                AVG(inv.AC1W) AS AC1W,
                                AVG(inv.AC1F) AS AC1F,
                                AVG(inv.AC1WH) AS AC1WH,
                                AVG(inv.AC2V) AS AC2V,
                                AVG(inv.AC2A) AS AC2A,
                                AVG(inv.AC2W) AS AC2W,
                                AVG(inv.AC2F) AS AC2F,
                                AVG(inv.AC2WH) AS AC2WH,
                                AVG(inv.AC3V) AS AC3V,
                                AVG(inv.AC3A) AS AC3A,
                                AVG(inv.AC3W) AS AC3W,
                                AVG(inv.AC3F) AS AC3F,
                                AVG(inv.AC3WH) AS AC3WH,
                                AVG(inv.DC1V) AS DC1V,
                                AVG(inv.DC1A) AS DC1A,
                                AVG(inv.DC1W) AS DC1W,
                                AVG(inv.DC1WH) AS DC1WH,
                                AVG(inv.DC2V) AS DC2V,
                                AVG(inv.DC2A) AS DC2A,
                                AVG(inv.DC2W) AS DC2W,
                                AVG(inv.DC2WH) AS DC2WH,
                                AVG(inv.DC3V) AS DC3V,
                                AVG(inv.DC3A) AS DC3A,
                                AVG(inv.DC3W) AS DC3W,
                                AVG(inv.DC3WH) AS DC3WH,
                                AVG(inv.DC4V) AS DC4V,
                                AVG(inv.DC4A) AS DC4A,
                                AVG(inv.DC4W) AS DC4W,
                                AVG(inv.DC4WH) AS DC4WH,
                                AVG(inv.DC5V) AS DC5V,
                                AVG(inv.DC5A) AS DC5A,
                                AVG(inv.DC5W) AS DC5W,
                                AVG(inv.DC5WH) AS DC5WH,
                                AVG(inv.PR) AS PR,
                                AVG(inv.RA1) AS RA1,
                                AVG(inv.RA2) AS RA2,
                                AVG(inv.RA3) AS RA3,
                                AVG(inv.RA4) AS RA4,
                                AVG(inv.RA5) AS RA5,
                                SUM(inv.KWH) AS KWH,
                                AVG(inv.TODAYKWH) AS TODAYKWH,
                                MAX(inv.TOTALKWH) AS TOTALKWH,
                                SUM(inv.KWH) / i.Capacity AS KWHKWP
                                FROM inverter_history_day inv 
                                LEFT JOIN {db_name}.inverter i ON CONCAT('s', inv.INVERTERID) = i.InverterId
                                WHERE DATE_FORMAT(inv.TIMESTAMP, '%Y-%m') = @Month
                                AND inv.PowerStationId = @PowerStationId
                                GROUP BY DATE_FORMAT(inv.TIMESTAMP, '%Y-%m'), inv.INVERTERID";
                    result = (await conn.QueryAsync<InverterHistory>(sql, new { Month = month, PowerStationId = powerStationId })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<A> Getonediv<A>(string where, string db_name, string table_name)
        {
            A result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $"SELECT sh.*,inv.*,con.Id,con.PowerStationId FROM {db_name}.{table_name} WHERE {where}";

                    result = await conn.QueryFirstOrDefaultAsync<A>(sql);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<int> AddInverterHistory(List<InverterHistory> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "inverter_history_hour");

                        count = await conn.ExecuteAsync(sql, entity, trans, commandTimeout: 600);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<int> AddInverterHistoryMonthList(List<InverterHistory> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "inverter_history_month");

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<int> UpdateInverterHistoryMonthList(List<InverterHistory> entity)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = @"UPDATE inverter_history_month SET
                                        KWH=@KWH,
                                        TODAYKWH=@TODAYKWH,
                                        KWHKWP=@KWHKWP
                                        WHERE PowerStationId = @PowerStationId
                                        AND TIMESTAMP LIKE CONCAT(@TIMESTAMP, '%')
                                        AND INVERTERID = @INVERTERID";

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<List<int>> GetPowerStationIdsByUserRole(MyUser myUser)
        {
            List<int> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = "";

                    if (myUser.Role.Layer == (int)RoleLayerEnum.CompanyAdmin)
                    {
                        sql += @$"SELECT ps.Id FROM power_station ps WHERE ps.Deleted = 0 AND ps.CompanyId = @CompanyId";
                    }
                    else if (myUser.Role.Layer == (int)RoleLayerEnum.CompanyUser)
                    {
                        sql += @$"SELECT op.PowerStationId FROM power_station_operation_personnel op WHERE op.Deleted = 0 AND UserId = @UserId";
                    }
                    else
                    {
                        sql += @$"SELECT ps.Id FROM power_station ps WHERE ps.Deleted = 0";
                    }

                    result = (await conn.QueryAsync<int>(sql, new { CompanyId = myUser.CompanyId, UserId = myUser.Id })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task AddWeatherObservation(List<WeatherObservation> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "weather_observation");

                        count = await conn.ExecuteAsync(sql, entity, trans, commandTimeout: 600);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }
        public async Task AddWeatherForecast(List<WeatherForecast> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "weather_forecast");

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        public async Task<NowWeather> SelectNowWeather(int CityId)
        {
            NowWeather result = new NowWeather();
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                var now = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                try
                {
                    var sql = @$"SELECT wf.PoP, wd.WeatherKey
                                FROM city c 
                                LEFT JOIN weather_forecast wf ON wf.LocationName = c.`Name` 
                                LEFT JOIN weather_description wd ON wd.WeatherName = wf.Wx  
                                WHERE c.Id = {CityId} AND '{now}' BETWEEN wf.StartTime AND wf.EndTime ORDER BY wf.CreatedAt desc";

                    result = await conn.QueryFirstOrDefaultAsync<NowWeather>(sql, commandTimeout: 600);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<MoneyAndCarbon> GetMoneyAndCarbonWithHistoryHour(int powerstationId, string dateTime, int type)
        {
            MoneyAndCarbon result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = "";
                    if (type == 0)
                    {
                        sql = $@"SELECT SUM(MONEY) AS MONEY, SUM(CARBON) AS CARBON FROM power_station_history_hour 
                                    WHERE PowerStationId = {powerstationId} AND DATE_FORMAT(`TIMESTAMP`,'%Y-%m') = '{dateTime}' ";
                    }
                    else
                    {
                        sql = $@"SELECT SUM(MONEY) AS MONEY, SUM(CARBON) AS CARBON FROM power_station_history_hour 
                                    WHERE PowerStationId = {powerstationId} AND DATE_FORMAT(`TIMESTAMP`,'%Y-%m-%d') = '{dateTime}' ";
                    }
                    result = await conn.QueryFirstOrDefaultAsync<MoneyAndCarbon>(sql);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<MoneyAndCarbon> GetLastMoneyAndCarbonInHour(int powerstationId, int type, string time)
        {
            MoneyAndCarbon result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                var tablename = "";
                if (type == 0)
                {
                    tablename = "power_station_history_hour";
                }
                else if (type == 1)
                {
                    tablename = "power_station_history_day";
                }
                else
                {
                    tablename = "power_station_history_month";
                }


                try
                {
                    var sql = "";
                    if (type == 0)
                    {
                        var time2 = time.Split(' ');
                        sql = $@"SELECT(SELECT TODAYMONEY FROM power_station_history_hour WHERE PowerStationId = {powerstationId} AND DATE_FORMAT(`TIMESTAMP`, '%Y-%m-%d') = '{time2[0]}' order by TIMESTAMP desc limit 1) AS TODAYMONEY,
                        TOTALMONEY,
                        (SELECT TODAYCARBON FROM power_station_history_hour WHERE PowerStationId = {powerstationId} AND DATE_FORMAT(`TIMESTAMP`, '%Y-%m-%d') = '{time2[0]}' order by TIMESTAMP desc limit 1) AS TODAYCARBON,
                         TOTALCARBON
                        FROM power_station_history_hour WHERE PowerStationId = {powerstationId} order by TIMESTAMP desc limit 1";
                    }
                    else
                    {
                        sql = $@"SELECT TOTALMONEY,TOTALCARBON FROM {tablename} 
                                    WHERE PowerStationId = {powerstationId} order by TIMESTAMP desc limit 1";
                    }

                    result = await conn.QueryFirstOrDefaultAsync<MoneyAndCarbon>(sql);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<string> ExistTable(string db_name, string table_name)
        {
            string result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = @DBName AND TABLE_NAME = @TableName;";

                    result = await conn.QueryFirstOrDefaultAsync<string>(sql, new { DBName = db_name, TableName = table_name }, commandTimeout: 600);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<SensorAvgHistory> CalcSensorAvgHistory(string dateTime, string table_name)
        {
            SensorAvgHistory result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sensor_str = "";
                    for (var i = 1; i <= 50; i++)
                    {
                        if (i < 10)
                        {
                            sensor_str += "AVG(SENSORAVG" + "0" + i.ToString() + ") AS SENSORAVG" + "0" + i.ToString() + ",";
                        }
                        else
                        {
                            sensor_str += "AVG(SENSORAVG" + i.ToString() + ") AS SENSORAVG" + i.ToString() + ",";
                        }
                    }

                    sensor_str = sensor_str.Substring(0, sensor_str.Length - 1);

                    var sql = @$"SELECT
                                    FROM_UNIXTIME(timestamp / 1000, '%Y-%m-%d %H') AS TIMESTAMP,
                                    {sensor_str}
                                    FROM {table_name}
                                    WHERE FROM_UNIXTIME(timestamp / 1000, '%Y-%m-%d %H') = @DateTime
                                    GROUP BY FROM_UNIXTIME(timestamp / 1000, '%Y-%m-%d %H')";


                    result = await conn.QueryFirstOrDefaultAsync<SensorAvgHistory>(sql, new { DateTime = dateTime }, commandTimeout: 600);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<int> AddSensorAvgHistory(List<SensorAvgHistory> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "sensoravg_history_hour");

                        count = await conn.ExecuteAsync(sql, entity, trans, commandTimeout: 600);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }

            return count;
        }

        public async Task<SensorAvgHistory> CalcSensorAvgDayDataByPowerStationId(string nowDay, int powerStationId)
        {
            SensorAvgHistory result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sensor_str = "";
                    for (var i = 1; i <= 50; i++)
                    {
                        if (i < 10)
                        {
                            sensor_str += "AVG(SENSORAVG" + "0" + i.ToString() + ") AS SENSORAVG" + "0" + i.ToString() + ",";
                        }
                        else
                        {
                            sensor_str += "AVG(SENSORAVG" + i.ToString() + ") AS SENSORAVG" + i.ToString() + ",";
                        }
                    }

                    sensor_str = sensor_str.Substring(0, sensor_str.Length - 1);

                    var sql = @$"SELECT
                                    PowerStationId,
                                    DATE_FORMAT(TIMESTAMP, '%Y-%m-%d') AS TIMESTAMP,
                                    {sensor_str}
                                    FROM sensoravg_history_hour
                                    WHERE PowerStationId = @PowerStationId
                                    AND DATE_FORMAT(TIMESTAMP, '%Y-%m-%d') = @NowDay
                                    GROUP BY DATE_FORMAT(timestamp, '%Y-%m-%d')";


                    result = await conn.QueryFirstOrDefaultAsync<SensorAvgHistory>(sql, new { PowerStationId = powerStationId, NowDay = nowDay });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<int> AddSensorAvgHistoryDayList(List<SensorAvgHistory> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "sensoravg_history_day");

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<SensorAvgHistory> GetSensorAvgHistoryByPowerStationIdAndMonth(string month, int powerStationId)
        {
            SensorAvgHistory result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT * FROM sensoravg_history_month WHERE DATE_FORMAT(TIMESTAMP, '%Y-%m') = @Month AND PowerStationId = @PowerStationId";
                    result = await conn.QueryFirstOrDefaultAsync<SensorAvgHistory>(sql, new { Month = month, PowerStationId = powerStationId });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<SensorAvgHistory> CalcSensorAvgHistoryMonthDataByPowerStationId(string month, int powerStationId)
        {
            SensorAvgHistory result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sensor_str = "";
                    for (var i = 1; i <= 50; i++)
                    {
                        if (i < 10)
                        {
                            sensor_str += "AVG(SENSORAVG" + "0" + i.ToString() + ") AS SENSORAVG" + "0" + i.ToString() + ",";
                        }
                        else
                        {
                            sensor_str += "AVG(SENSORAVG" + i.ToString() + ") AS SENSORAVG" + i.ToString() + ",";
                        }
                    }

                    sensor_str = sensor_str.Substring(0, sensor_str.Length - 1);

                    var sql = @$"SELECT
                                    PowerStationId,
                                    DATE_FORMAT(TIMESTAMP, '%Y-%m') AS TIMESTAMP,
                                    {sensor_str}
                                    FROM sensoravg_history_day
                                    WHERE PowerStationId = @PowerStationId
                                    AND DATE_FORMAT(TIMESTAMP, '%Y-%m')  = @Month
                                    GROUP BY DATE_FORMAT(TIMESTAMP, '%Y-%m')";

                    result = await conn.QueryFirstOrDefaultAsync<SensorAvgHistory>(sql, new { Month = month, PowerStationId = powerStationId });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<int> AddSensorAvgHistoryMonthList(List<SensorAvgHistory> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "sensoravg_history_month");

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<int> UpdateSensorAvgHistoryMonthList(List<SensorAvgHistory> entity)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sensor_str = "";
                        for (var i = 1; i <= 50; i++)
                        {
                            if (i < 10)
                            {
                                sensor_str += "SENSORAVG" + "0" + i.ToString() + " = @SENSORAVG" + "0" + i.ToString() + ",";
                            }
                            else
                            {
                                sensor_str += "SENSORAVG" + i.ToString() + " = @SENSORAVG" + i.ToString() + ",";
                            }

                        }

                        sensor_str = sensor_str.Substring(0, sensor_str.Length - 1);

                        string sql = @$"UPDATE sensoravg_history_month SET
                                        {sensor_str}
                                        WHERE PowerStationId = @PowerStationId
                                        AND TIMESTAMP LIKE CONCAT(@TIMESTAMP, '%')";

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<MeterHistory> CalcMeterHistory(string dateTime, string table_name)
        {
            MeterHistory result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT 
	                                m1.timestamp,
                                    m1.METERID,
	                                m1.V_AB,
	                                m1.V_BC,
	                                m1.V_CA,
	                                m1.I_A,
	                                m1.I_B,
	                                m1.I_C,
	                                m1.P,
	                                m1.F,
	                                m2.INPUT_KWH,
	                                m2.OUTPUT_KWH
	                            FROM ( -- 取得平均值
                                    SELECT 
                                        FROM_UNIXTIME(m.timestamp / 1000, '%Y-%m-%d %H') AS timestamp,
                                        m.METERID,
                                        AVG(m.V_AB) AS V_AB,
	                                    AVG(m.V_BC) AS V_BC,
	                                    AVG(m.V_CA) AS V_CA,
	                                    AVG(m.I_A) AS I_A,
	                                    AVG(m.I_B) AS I_B,
	                                    AVG(m.I_C) AS I_C,
	                                    AVG(m.P) AS P,
	                                    AVG(m.F) AS F
                                    FROM {table_name} m
                                    WHERE FROM_UNIXTIME(m.timestamp / 1000, '%Y-%m-%d %H') = @DateTime
                                    GROUP BY FROM_UNIXTIME(m.timestamp / 1000, '%Y-%m-%d %H'), m.METERID
                                ) m1
	                            LEFT JOIN ( -- 取得整點值INPUT_KWH, OUTPUT_KWH
	                                SELECT 
	                                    FROM_UNIXTIME(m.timestamp / 1000, '%Y-%m-%d %H') AS timestamp,
                                        m.METERID,
	                                    m.INPUT_KWH AS INPUT_KWH,
	                                    m.OUTPUT_KWH AS OUTPUT_KWH
	                                FROM {table_name} m
                                    WHERE LEFT(FROM_UNIXTIME(m.timestamp / 1000, '%Y-%m-%d %H'), 10) = @DateTime
	                                AND RIGHT(FROM_UNIXTIME(m.timestamp / 1000, '%Y-%m-%d %H'), 2) = '55' ) m2 
	                            ON m1.timestamp = m2.timestamp AND m1.METERID = m2.METERID";
                    result = await conn.QueryFirstOrDefaultAsync<MeterHistory>(sql, new { DateTime = dateTime }, commandTimeout: 600);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<int> AddMeterHistory(List<MeterHistory> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "meter_history_hour");

                        count = await conn.ExecuteAsync(sql, entity, trans, commandTimeout: 600);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }

            return count;
        }

        //TODO: 電表每日彙整
        public async Task<List<MeterHistory>> CalcMeterDayDataByPowerStationId(string nowDay, int powerStationId)
        {
            List<MeterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {

                    var sql = $@"SELECT 
                                m.PowerStationId,
                                DATE_FORMAT(m.TIMESTAMP, '%Y-%m-%d') AS TIMESTAMP,
                                m.METERID,
                                AVG(m.V_AB) AS V_AB,
                                AVG(m.V_BC) AS V_BC,
                                AVG(m.V_CA) AS V_CA,
                                AVG(m.I_A) AS I_A,
                                AVG(m.I_B) AS I_B,
                                AVG(m.I_C) AS I_C,
                                AVG(m.P) AS P,
                                AVG(m.F) AS F,
                                AVG(m.INPUT_KWH) AS INPUT_KWH,
                                AVG(m.OUTPUT_KWH) AS OUTPUT_KWH
                                FROM meter_history_hour m 
                                WHERE DATE_FORMAT(m.TIMESTAMP, '%Y-%m-%d') = @NowDay
                                AND m.PowerStationId = @PowerStationId
                                GROUP BY DATE_FORMAT(m.TIMESTAMP, '%Y-%m-%d'), m.METERID";

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

        public async Task<int> AddMeterHistoryDayList(List<MeterHistory> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "meter_history_day");

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<List<MeterHistory>> GetMeterHistoryByPowerStationIdAndMonth(string month, int powerStationId)
        {
            List<MeterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT * FROM meter_history_month WHERE DATE_FORMAT(TIMESTAMP, '%Y-%m') = @Month AND PowerStationId = @PowerStationId";
                    result = (await conn.QueryAsync<MeterHistory>(sql, new { Month = month, PowerStationId = powerStationId })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<List<MeterHistory>> CalcMeterHistoryMonthDataByPowerStationId(string month, int powerStationId)
        {
            List<MeterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT 
                                m.PowerStationId,
                                DATE_FORMAT(m.TIMESTAMP, '%Y-%m') AS TIMESTAMP,
                                m.METERID,
                                AVG(m.V_AB) AS V_AB,
                                AVG(m.V_BC) AS V_BC,
                                AVG(m.V_CA) AS V_CA,
                                AVG(m.I_A) AS I_A,
                                AVG(m.I_B) AS I_B,
                                AVG(m.I_C) AS I_C,
                                AVG(m.P) AS P,
                                AVG(m.F) AS F,
                                AVG(m.INPUT_KWH) AS INPUT_KWH,
                                AVG(m.OUTPUT_KWH) AS OUTPUT_KWH
                                FROM meter_history_day m 
                                WHERE DATE_FORMAT(m.TIMESTAMP, '%Y-%m') = @Month
                                AND m.PowerStationId = @PowerStationId
                                GROUP BY DATE_FORMAT(m.TIMESTAMP, '%Y-%m'), m.METERID";
                    result = (await conn.QueryAsync<MeterHistory>(sql, new { Month = month, PowerStationId = powerStationId })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<int> AddMeterHistoryMonthList(List<MeterHistory> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "meter_history_month");

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }

        public async Task<int> UpdateMeterHistoryMonthList(List<MeterHistory> entity)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = @"UPDATE meter_history_month SET
                                        V_AB=@V_AB,
                                        V_BC=@V_BC,
                                        V_CA=@V_CA,
                                        I_A=@I_A,
                                        I_B=@I_B,
                                        I_C=@I_C,
                                        P=@P,
                                        F=@F,
                                        INPUT_KWH=@INPUT_KWH,
                                        OUTPUT_KWH=@OUTPUT_KWH
                                        WHERE PowerStationId = @PowerStationId
                                        AND TIMESTAMP LIKE CONCAT(@TIMESTAMP, '%')
                                        AND METERID = @METERID";

                        count = await conn.ExecuteAsync(sql, entity, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }

                return count;
            }
        }


        public async Task<List<PowerStation>> GetPowerStationsByCompanyId(MyUser myUser)
        {
            List<PowerStation> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $"SELECT ps.* FROM {tableName} ps";

                    if (myUser.Role.Layer == 2)
                    {
                        sql += " WHERE ps.Deleted = 0 AND ps.CompanyId = @CompanyId ";
                    }
                    else
                    {
                        sql += @" LEFT JOIN power_station_operation_personnel op ON ps.Id = op.PowerStationId
                                    WHERE ps.Deleted = 0 AND op.Deleted = 0 AND op.UserId = @UserId ";
                    }

                    result = (await conn.QueryAsync<PowerStation>(sql, new { CompanyId = myUser.CompanyId, UserId = myUser.Id })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<List<PowerStationInverter>> GetPowerStationInverter(Dictionary<string, List<int>> dic, string filter)
        {
            List<PowerStationInverter> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    List<string> sql_perSiteDB = new List<string>();
                    var sql = "";
                    foreach (var powerStationDic in dic)
                    {
                        var powerStationIds = string.Join(",", powerStationDic.Value);

                        var temp_sql = @$"SELECT ps.Id AS PowerStationId,
                                            c.Priority AS Priority,
                                            c.Name AS CityName,
                                            ps.Name AS PowerStationName,
                                            inv.InverterName AS InverterName,
                                            inv.InverterId AS InverterId,
                                            inv.CreatedAt
                                    FROM power_station ps 
                                    LEFT JOIN `city` c ON ps.CityId = c.Id
                                    LEFT JOIN {powerStationDic.Key}.controller con ON ps.Id = con.PowerStationId
                                    LEFT JOIN {powerStationDic.Key}.inverter inv ON con.Id = inv.ControllerId AND inv.Enabled = 1 AND inv.status != 0
                                    WHERE ps.Deleted = 0 
                                    AND ps.Id IN ({powerStationIds})";
                        if (!string.IsNullOrEmpty(filter))
                        {
                            temp_sql += " AND inv.InverterName LIKE CONCAT('%', @Filter, '%')";
                        }

                        sql_perSiteDB.Add(temp_sql);
                    }

                    sql = string.Join(" UNION ", sql_perSiteDB);
                    sql = "(" + sql + ") ORDER BY Priority, CreatedAt";

                    result = (await conn.QueryAsync<PowerStationInverter>(sql, new { Filter = filter })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<List<PowerStationDevice>> GetPowerStationDevice(Dictionary<string, List<int>> dic, string filter)
        {
            List<PowerStationDevice> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    List<string> sql_perSiteDB = new List<string>();
                    var sql = "";
                    foreach (var powerStationDic in dic)
                    {
                        var powerStationIds = string.Join(",", powerStationDic.Value);

                        var temp_sql = @$"SELECT ps.Id AS PowerStationId,
                                            c.Priority AS Priority,
                                            c.Name AS CityName,
                                            ps.Name AS PowerStationName,
                                            d.Name AS DeviceName,
                                            d.`Type` AS DeviceType,
                                            d.UID AS DeviceId,
                                            d.SensorTypeId AS SensorTypeId,
                                            d.SensorTypeDetailId AS SensorTypeDetailId
                                    FROM power_station ps 
                                    LEFT JOIN `city` c ON ps.CityId = c.Id
                                    LEFT JOIN {powerStationDic.Key}.device d ON ps.Id = d.PowerStationId AND d.Deleted = 0 AND d.Enabled = 1 AND d.Status = 1
                                    WHERE ps.Deleted = 0 
                                    AND ps.Id IN ({powerStationIds})";
                        if (!string.IsNullOrEmpty(filter))
                        {
                            temp_sql += " AND d.Name LIKE CONCAT('%', @Filter, '%')";
                        }

                        sql_perSiteDB.Add(temp_sql);
                    }

                    sql = string.Join(" UNION ", sql_perSiteDB);

                    sql = "(" + sql + ") ORDER BY Priority";

                    result = (await conn.QueryAsync<PowerStationDevice>(sql, new { Filter = filter })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<List<InverterHistory>> GetInverterHistoryRowData(long start_timestamp, long end_timestamp, List<StationCodeWithInverterIds> entities)
        {
            List<InverterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    List<string> sql_perSiteDB = new List<string>();
                    var sql = "";
                    foreach (var entity in entities)
                    {
                        var table_name = string.Format("`{0}`.`s{1}01_inv`", entity.SiteDB, entity.Code);
                        var sensor_table_name = string.Format("`{0}`.`s{1}01_sensoravg`", entity.SiteDB, entity.Code);
                        var inverterIds = string.Join("','", entity.InverterIds);

                        var temp_sql = $@"SELECT 
                                FROM_UNIXTIME(inv.TIMESTAMP/1000, '%H:%i') AS TIMESTAMP,
                                inv.INVERTERID,
                                i.InverterName AS INVERTERName,
                                sen.{entity.Sensor} AS Irradiance,
                                ((inv.DC1W + inv.DC2W + inv.DC3W + inv.DC4W + inv.DC5W) / 1000) AS DCKW,
                                ((inv.AC1W + inv.AC2W + inv.AC3W) / 1000) AS ACKW,
                                inv.AC1V,
                                inv.AC1A,
                                inv.AC1W,
                                inv.AC1F,
                                inv.AC1WH,
                                inv.AC2V,
                                inv.AC2A,
                                inv.AC2W,
                                inv.AC2F,
                                inv.AC2WH,
                                inv.AC3V,
                                inv.AC3A,
                                inv.AC3W,
                                inv.AC3F,
                                inv.AC3WH,
                                inv.DC1V,
                                inv.DC1A,
                                inv.DC1W,
                                inv.DC1WH,
                                inv.DC2V,
                                inv.DC2A,
                                inv.DC2W,
                                inv.DC2WH,
                                inv.DC3V,
                                inv.DC3A,
                                inv.DC3W,
                                inv.DC3WH,
                                inv.DC4V,
                                inv.DC4A,
                                inv.DC4W,
                                inv.DC4WH,
                                inv.DC5V,
                                inv.DC5A,
                                inv.DC5W,
                                inv.DC5WH,
                                inv.PR,
                                inv.RA1,
                                inv.RA2,
                                inv.RA3,
                                inv.RA4,
                                inv.RA5
                                FROM {table_name} inv
                                LEFT JOIN (select * from {sensor_table_name} where TIMESTAMP between @start_timestamp and @end_timestamp)sen 
                                ON inv.CrdTime = sen.CrdTime
                                -- LEFT JOIN {sensor_table_name} sen ON FROM_UNIXTIME(inv.TIMESTAMP/1000, '%Y-%m-%d %H:%i') = FROM_UNIXTIME(sen.TIMESTAMP/1000, '%Y-%m-%d %H:%i')
                                LEFT JOIN {entity.SiteDB}.inverter i ON inv.INVERTERID = i.InverterId
                                WHERE inv.`TIMESTAMP` between @start_timestamp and @end_timestamp
                                -- WHERE FROM_UNIXTIME(inv.TIMESTAMP/1000, '%Y-%m-%d') = @NowDay 
                                AND inv.INVERTERID IN ('{inverterIds}')";

                        sql_perSiteDB.Add(temp_sql);
                    }
                    sql = "SELECT * FROM (" + string.Join(" UNION ", sql_perSiteDB) + ") a ORDER BY a.TIMESTAMP ASC";

                    result = (await conn.QueryAsync<InverterHistory>(sql, new { start_timestamp = start_timestamp, end_timestamp = end_timestamp }, commandTimeout: 300)).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<List<InverterHistory>> GetInverterHistoryByDate(string startDay, string endDay, List<StationIdWithInverterIds> entities)
        {
            List<InverterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    List<string> sql_perSiteDB = new List<string>();
                    var sql = "";
                    foreach (var entity in entities)
                    {
                        var inverterIds = string.Join("','", entity.InverterIds);

                        var temp_sql = $@"SELECT 
                                    DATE_FORMAT(inv.TIMESTAMP, '%Y-%m-%d') AS TIMESTAMP,
                                    inv.INVERTERID,
                                    i.InverterName AS INVERTERName,
                                    inv.Irradiance,
                                    inv.KWH,
                                    inv.TODAYKWH,
                                    inv.PR,
                                    inv.RA1,
                                    inv.RA2,
                                    inv.RA3,
                                    inv.RA4,
                                    inv.RA5
                                    FROM inverter_history_day inv 
                                    LEFT JOIN {entity.SiteDBName}.inverter i ON inv.INVERTERID = i.InverterId
                                    WHERE inv.PowerStationId = {entity.PowerStationId}
                                    AND inv.INVERTERID IN ('{inverterIds}')
                                    AND inv.TIMESTAMP BETWEEN @StartDay AND @EndDay";

                        sql_perSiteDB.Add(temp_sql);
                    }
                    sql = "SELECT * FROM (" + string.Join(" UNION ", sql_perSiteDB) + ") a ORDER BY a.TIMESTAMP ASC";

                    result = (await conn.QueryAsync<InverterHistory>(sql, new { StartDay = startDay, EndDay = endDay })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<List<InverterHistory>> GetInverterHistoryByYear(string year, List<StationIdWithInverterIds> entities)
        {
            List<InverterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    List<string> sql_perSiteDB = new List<string>();
                    var sql = "";
                    foreach (var entity in entities)
                    {
                        var inverterIds = string.Join("','", entity.InverterIds);

                        var temp_sql = $@"SELECT 
                                    DATE_FORMAT(inv.TIMESTAMP, '%Y-%m-%d') AS TIMESTAMP,
                                    inv.INVERTERID,
                                    i.InverterName AS INVERTERName,
                                    inv.KWH,
                                    inv.TODAYKWH,
                                    inv.PR,
                                    inv.RA1,
                                    inv.RA2,
                                    inv.RA3,
                                    inv.RA4,
                                    inv.RA5
                                    FROM inverter_history_month inv 
                                    LEFT JOIN {entity.SiteDBName}.inverter i ON inv.INVERTERID = i.InverterId
                                    WHERE inv.PowerStationId = {entity.PowerStationId}
                                    AND inv.INVERTERID IN ('{inverterIds}')
                                    AND DATE_FORMAT(inv.TIMESTAMP, '%Y') = @Year";

                        sql_perSiteDB.Add(temp_sql);
                    }
                    sql = string.Join(" UNION ", sql_perSiteDB);

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


        public async Task<List<PowerStationIdAndCity>> GetPowerStationsByCompanyIdWithfilter(MyUser myUser, string filter)
        {
            List<PowerStationIdAndCity> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT ps.Id AS PowerStationId , ps.`Name` AS PowerStationName,c.Name AS CityName FROM {tableName} ps
                                LEFT JOIN city c ON c.Id = ps.CityId";

                    if (myUser.Role.Layer == 2)
                    {
                        sql += " WHERE ps.Deleted = 0 AND ps.CompanyId = @CompanyId ";
                    }
                    else
                    {
                        sql += @" LEFT JOIN power_station_operation_personnel op ON ps.Id = op.PowerStationId
                                    WHERE ps.Deleted = 0 AND op.Deleted = 0 AND op.UserId = @UserId ";
                    }

                    if (!string.IsNullOrEmpty(filter))
                    {
                        sql += @" AND ps.Name LIKE CONCAT('%', @Filter, '%')";
                    }

                    sql += " ORDER BY c.Priority";
                    result = (await conn.QueryAsync<PowerStationIdAndCity>(sql, new { CompanyId = myUser.CompanyId, UserId = myUser.Id, Filter = filter })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<List<PowerStationIdAndCity>> GetPowerStationsAllWithfilter(string filter)
        {
            List<PowerStationIdAndCity> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT ps.Id AS PowerStationId , ps.`Name` AS PowerStationName,c.Name AS CityName FROM {tableName} ps
                                LEFT JOIN city c ON c.Id = ps.CityId WHERE ps.Deleted = 0 ";


                    if (!string.IsNullOrEmpty(filter))
                    {
                        sql += @" AND ps.Name LIKE CONCAT('%', @Filter, '%')";
                    }

                    sql += " ORDER BY c.Priority";
                    result = (await conn.QueryAsync<PowerStationIdAndCity>(sql, new { Filter = filter })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<List<Device>> GetDeviceByPowerStationIdAndDeviceIds(string db_name, int powerStationId, List<string> deviceIds)
        {
            List<Device> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT * FROM {db_name}.device d
                                    WHERE d.PowerStationId = @PowerStationId AND UID IN @UID AND Deleted = 0 AND Enabled = 1";


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

        public async Task<dynamic> GetSensorAvgByDevices(string date, byte searchType, List<Device> devices)
        {
            dynamic result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var date_format = "";
                    var table_name = "";
                    var where_date = "";

                    var start_date = "";
                    var end_date = "";
                    switch (searchType)
                    {
                        case 0:
                            date_format = "%H:%i";
                            table_name = "sensoravg_history_hour";
                            where_date = $" DATE_FORMAT(sen.TIMESTAMP, '%Y-%m-%d') = '{date}'";
                            break;
                        case 1:
                            date_format = "%Y-%m-%d";
                            table_name = "sensoravg_history_day";

                            var date_split = date.Split('-');
                            start_date = Convert.ToDateTime(date_split[0].Trim()).ToString("yyyy-MM-dd");
                            end_date = Convert.ToDateTime(date_split[1].Trim()).ToString("yyyy-MM-dd");
                            where_date = $" DATE_FORMAT(sen.TIMESTAMP, '%Y-%m-%d') BETWEEN '{start_date}' AND '{end_date}'";
                            break;
                        case 2:
                            date_format = "%Y-%m-%d";
                            table_name = "sensoravg_history_day";
                            start_date = Convert.ToDateTime(date).ToString("yyyy-MM-dd");
                            end_date = Convert.ToDateTime(date).AddMonths(1).AddDays(-1).ToString("yyyy-MM-dd");
                            where_date = $" DATE_FORMAT(sen.TIMESTAMP, '%Y-%m-%d') BETWEEN '{start_date}' AND '{end_date}'";
                            break;
                        case 3:
                            date_format = "%Y-%m";
                            table_name = "sensoravg_history_month";
                            where_date = $" DATE_FORMAT(sen.TIMESTAMP, '%Y') = '{date}'";
                            break;
                    }

                    List<string> sql_select_col = new List<string>();
                    var sql_sub = "";

                    for (var i = 0; i < devices.Count(); i++)
                    {
                        if (i == 0)
                        {
                            sql_select_col.Add($"DATE_FORMAT(sen.TIMESTAMP, '{date_format}') AS TIMESTAMP");
                            sql_select_col.Add(string.Concat("`", devices[i].UID, "`"));

                            sql_sub += @$" FROM (SELECT sen.TIMESTAMP, sen.{devices[i].ColName} AS `{devices[i].UID}` FROM {table_name} sen WHERE sen.PowerStationId = {devices[i].PowerStationId} AND {where_date}) sen";
                        }
                        else
                        {
                            sql_select_col.Add(string.Concat("`", devices[i].UID, "`"));

                            sql_sub += @$" LEFT JOIN (
                                                SELECT sen.TIMESTAMP, sen.{devices[i].ColName} AS `{devices[i].UID}`
                                                FROM {table_name} sen
                                                WHERE sen.PowerStationId = {devices[i].PowerStationId} AND {where_date}) sen{i}
                                           ON sen.TIMESTAMP = sen{i}.TIMESTAMP";
                        }
                    }

                    var select_col = string.Join(", ", sql_select_col);
                    var sql = $"SELECT {select_col} " + sql_sub + " ORDER BY sen.TIMESTAMP";

                    result = await conn.QueryAsync<dynamic>(sql);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        /// <summary>
        /// 電站資訊 - history - 下方表格
        /// </summary>
        /// <param name="date"></param>
        /// <param name="searchType"></param>
        /// <param name="entities"></param>
        /// <returns></returns>
        public async Task<List<PowerStationHistory>> GetPowerStationHistory(string date, byte searchType, List<int> entities)
        {
            List<PowerStationHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var KWH_col = "";
                    var date_format = "";
                    var table_name = "";
                    var where_date = "";
                    var letf_join_table = "";

                    var start_date = "";
                    var end_date = "";
                    switch (searchType)
                    {
                        case 0:
                            KWH_col = "ps.KWH";
                            date_format = "%H:%i";
                            table_name = "power_station_history_hour";
                            letf_join_table = "sensor_history_hour";
                            where_date = $" AND DATE_FORMAT(ps.TIMESTAMP, '%Y-%m-%d') = '{date}'";
                            break;
                        case 1:
                            KWH_col = "ps.TODAYKWH AS KWH";
                            date_format = "%Y-%m-%d";
                            table_name = "power_station_history_day";
                            letf_join_table = "sensor_history_day";
                            var date_split = date.Split('-');
                            start_date = Convert.ToDateTime(date_split[0].Trim()).ToString("yyyy-MM-dd");
                            end_date = Convert.ToDateTime(date_split[1].Trim()).ToString("yyyy-MM-dd");
                            where_date = $" AND DATE_FORMAT(ps.TIMESTAMP, '%Y-%m-%d') BETWEEN '{start_date}' AND '{end_date}'";
                            break;
                        case 2:
                            KWH_col = "ps.TODAYKWH AS KWH";
                            date_format = "%Y-%m-%d";
                            table_name = "power_station_history_day";
                            letf_join_table = "sensor_history_day";
                            start_date = Convert.ToDateTime(date).ToString("yyyy-MM-dd");
                            end_date = Convert.ToDateTime(date).AddMonths(1).AddDays(-1).ToString("yyyy-MM-dd");
                            where_date = $" AND DATE_FORMAT(ps.TIMESTAMP, '%Y-%m-%d') BETWEEN '{start_date}' AND '{end_date}'";
                            break;
                        case 3:
                            KWH_col = "ps.MONTHKWH AS KWH";
                            date_format = "%Y-%m";
                            table_name = "power_station_history_month";
                            letf_join_table = "sensor_history_month";
                            where_date = $" AND DATE_FORMAT(ps.TIMESTAMP, '%Y') = '{date}'";
                            break;
                    }

                    var sql = $@"SELECT 
                                    ps.PowerStationId,
                                    DATE_FORMAT(ps.TIMESTAMP, '{date_format}') AS TIMESTAMP,
                                    {KWH_col},
                                    ps.SOLARHOUR,
                                    ps.KWHKWP,
                                    ps.PR,
                                    sen.Irradiance,
                                    sen.Temperature
                                    FROM {table_name} ps 
                                    LEFT JOIN {letf_join_table} sen ON ps.PowerStationId = sen.PowerStationId AND ps.TIMESTAMP = sen.TIMESTAMP
                                    WHERE ps.PowerStationId IN @PowerStationId
                                    {where_date}
                                    ORDER BY ps.TIMESTAMP";

                    result = (await conn.QueryAsync<PowerStationHistory>(sql, new { PowerStationId = entities })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        public async Task<List<MeterHistory>> GetMeterHistory(string date, byte searchType, List<StationIdWithMeterIds> entities)
        {
            List<MeterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var date_format = "";
                    var table_name = "";
                    var where_date = "";

                    var start_date = "";
                    var end_date = "";
                    switch (searchType)
                    {
                        case 0:
                            date_format = "%H:%i";
                            table_name = "meter_history_hour";
                            where_date = $" AND DATE_FORMAT(m.TIMESTAMP, '%Y-%m-%d') = '{date}'";
                            break;
                        case 1:
                            date_format = "%Y-%m-%d";
                            table_name = "meter_history_day";
                            var date_split = date.Split('-');
                            start_date = Convert.ToDateTime(date_split[0].Trim()).ToString("yyyy-MM-dd");
                            end_date = Convert.ToDateTime(date_split[1].Trim()).ToString("yyyy-MM-dd");
                            where_date = $" AND DATE_FORMAT(m.TIMESTAMP, '%Y-%m-%d') BETWEEN '{start_date}' AND '{end_date}'";
                            break;
                        case 2:
                            date_format = "%Y-%m-%d";
                            table_name = "power_station_history_day";
                            start_date = Convert.ToDateTime(date).ToString("yyyy-MM-dd");
                            end_date = Convert.ToDateTime(date).AddMonths(1).AddDays(-1).ToString("yyyy-MM-dd");
                            where_date = $" AND DATE_FORMAT(m.TIMESTAMP, '%Y-%m-%d') BETWEEN '{start_date}' AND '{end_date}'";
                            break;
                        case 3:
                            date_format = "%Y-%m";
                            table_name = "power_station_history_month";
                            where_date = $" AND DATE_FORMAT(m.TIMESTAMP, '%Y') = '{date}'";
                            break;
                    }

                    List<string> sql_perSiteDB = new List<string>();
                    var sql = "";
                    foreach (var entity in entities)
                    {
                        var meterIds = string.Join("','", entity.MeterIds);

                        var temp_sql = $@"SELECT 
                                    DATE_FORMAT(m.TIMESTAMP, '{date_format}') AS TIMESTAMP,
                                    m.METERID,
                                    m.V_AB,
                                    m.V_BC,
                                    m.V_CA,
                                    m.I_A,
                                    m.I_B,
                                    m.I_C,
                                    m.P,
                                    m.F,
                                    m.OUTPUT_KWH,
                                    m.INPUT_KWH
                                    FROM {table_name} m 
                                    WHERE m.PowerStationId = {entity.PowerStationId}
                                    AND m.METERID IN ('{meterIds}')
                                    {where_date}
                                    ORDER BY m.TIMESTAMP";

                        sql_perSiteDB.Add(temp_sql);
                    }
                    sql = string.Join(" UNION ", sql_perSiteDB);

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

        public async Task<List<PowerStationHistory>> GetPowerStationHistoryByDateRange(string startDate, string endDate)
        {
            List<PowerStationHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $"SELECT * FROM power_station_history_hour WHERE DATE_FORMAT(TIMESTAMP, '%Y-%m-%d') BETWEEN @StartDate AND @EndDate";

                    result = (await conn.QueryAsync<PowerStationHistory>(sql, new { StartDate = startDate, EndDate = endDate })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task AddAfterPurgePowerStationHistoryHour(string startDate, string endDate, List<PowerStationHistory> entity, List<string> properties)
        {
            int count;

            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var purge_sql = $"DELETE FROM power_station_history_hour WHERE DATE_FORMAT(TIMESTAMP, '%Y-%m-%d') BETWEEN @StartDate AND @EndDate";
                        await conn.ExecuteAsync(purge_sql, new { StartDate = startDate, EndDate = endDate }, trans);

                        var insert_sql = GenerateInsertQueryWithCustomTable(properties, "power_station_history_hour");
                        count = await conn.ExecuteAsync(insert_sql, entity, trans);

                        trans.Commit();

                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        public async Task AddAfterPurgePowerStationHistoryDay(string startDate, string endDate, List<PowerStationHistoryDay> entity, List<string> properties)
        {
            int count;

            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var purge_sql = $"DELETE FROM power_station_history_day WHERE DATE_FORMAT(TIMESTAMP, '%Y-%m-%d') BETWEEN @StartDate AND @EndDate";
                        await conn.ExecuteAsync(purge_sql, new { StartDate = startDate, EndDate = endDate }, trans);

                        var insert_sql = GenerateInsertQueryWithCustomTable(properties, "power_station_history_day");
                        count = await conn.ExecuteAsync(insert_sql, entity, trans);

                        trans.Commit();

                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        public async Task AddAfterPurgePowerStationHistoryMonth(string startDate, string endDate, List<PowerStationHistoryMonth> entity, List<string> properties)
        {
            int count;

            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var purge_sql = $"DELETE FROM power_station_history_month WHERE DATE_FORMAT(TIMESTAMP, '%Y-%m-%d') BETWEEN @StartDate AND @EndDate";
                        await conn.ExecuteAsync(purge_sql, new { StartDate = startDate, EndDate = endDate }, trans);

                        var insert_sql = GenerateInsertQueryWithCustomTable(properties, "power_station_history_month");
                        count = await conn.ExecuteAsync(insert_sql, entity, trans);

                        trans.Commit();

                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        public async Task AddAfterPurgePyrheliometerHistory(string startDate, string endDate, byte type, List<PyrheliometerHistory> entity, List<string> properties)
        {
            int count;

            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var table_name = "";
                        switch (type)
                        {
                            case 0: //小時
                                table_name = "sensor_history_hour";
                                break;
                            case 1:
                                table_name = "sensor_history_day";
                                break;
                            case 2:
                                table_name = "sensor_history_month";
                                break;
                        }

                        var purge_sql = $"DELETE FROM {table_name} WHERE DATE_FORMAT(TIMESTAMP, '%Y-%m-%d') BETWEEN @StartDate AND @EndDate";
                        await conn.ExecuteAsync(purge_sql, new { StartDate = startDate, EndDate = endDate }, trans);

                        var insert_sql = GenerateInsertQueryWithCustomTable(properties, table_name);
                        count = await conn.ExecuteAsync(insert_sql, entity, trans);

                        trans.Commit();

                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        public async Task AddAfterPurgeInverterHistory(string startDate, string endDate, byte type, List<InverterHistory> entity, List<string> properties)
        {
            int count;

            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var table_name = "";
                        switch (type)
                        {
                            case 0: //小時
                                table_name = "inverter_history_hour";
                                break;
                            case 1:
                                table_name = "inverter_history_day";
                                break;
                            case 2:
                                table_name = "inverter_history_month";
                                break;
                        }

                        var purge_sql = $"DELETE FROM {table_name} WHERE DATE_FORMAT(TIMESTAMP, '%Y-%m-%d') BETWEEN @StartDate AND @EndDate";
                        await conn.ExecuteAsync(purge_sql, new { StartDate = startDate, EndDate = endDate }, trans);

                        var insert_sql = GenerateInsertQueryWithCustomTable(properties, table_name);
                        count = await conn.ExecuteAsync(insert_sql, entity, trans);

                        trans.Commit();

                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        public async Task AddAfterPurgeInverterHistory15min(string startDate, string endDate, List<InverterHistory> entity, List<string> properties)
        {
            int count;

            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var table_name = "inverter_history_15min";

                        var purge_sql = $"DELETE FROM {table_name} WHERE DATE_FORMAT(TIMESTAMP, '%Y-%m-%d') BETWEEN @StartDate AND @EndDate";
                        await conn.ExecuteAsync(purge_sql, new { StartDate = startDate, EndDate = endDate }, trans);

                        var insert_sql = GenerateInsertQueryWithCustomTable(properties, table_name);
                        count = await conn.ExecuteAsync(insert_sql, entity, trans);

                        trans.Commit();

                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        public async Task AddAfterPurgeSensorAvgHistory(string startDate, string endDate, byte type, List<SensorAvgHistory> entity, List<string> properties)
        {
            int count;

            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var table_name = "";
                        switch (type)
                        {
                            case 0: //小時
                                table_name = "sensoravg_history_hour";
                                break;
                            case 1:
                                table_name = "sensoravg_history_day";
                                break;
                            case 2:
                                table_name = "sensoravg_history_month";
                                break;
                        }

                        var purge_sql = $"DELETE FROM {table_name} WHERE DATE_FORMAT(TIMESTAMP, '%Y-%m-%d') BETWEEN @StartDate AND @EndDate";
                        await conn.ExecuteAsync(purge_sql, new { StartDate = startDate, EndDate = endDate }, trans);

                        var insert_sql = GenerateInsertQueryWithCustomTable(properties, table_name);
                        count = await conn.ExecuteAsync(insert_sql, entity, trans);

                        trans.Commit();

                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        public async Task<bool> CheckShowMoney(int userid)
        {
            bool result = true;
            string J;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT ap.AuthCode FROM user u 
                                    LEFT JOIN role_auth ra ON ra.Id = u.RoleId 
                                    LEFT JOIN auth_page ap ON ap.AuthCode = ra.AuthCode 
                                    WHERE u.Id = {userid} AND ap.AuthCode = 'J' ";


                    J = await conn.QueryFirstOrDefaultAsync<string>(sql);
                    if (J == null)
                    {
                        result = false;
                    }
                    else
                    {
                        result = true;
                    }
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
            }
            return result;
        }

        public async Task<List<InverterHistory>> GetAllInverterRowData(string date, string table_name)
        {
            List<InverterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT FROM_UNIXTIME(`TIMESTAMP`/1000,'%Y-%m-%d') AS TIMESTAMP,
                                inv.WH / 1000 AS KWH,
                                inv.TODAYKWH,
                                inv.TOTALKWH
                                FROM {table_name} inv 
                                WHERE FROM_UNIXTIME(`TIMESTAMP`/1000,'%Y-%m-%d') = $Date";

                    result = (await conn.QueryAsync<InverterHistory>(sql, new { Date = date })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<List<InverterHistory>> GetAllInverterInfo(List<string> post, string site_table, string site_db)
        {
            List<InverterHistory> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT b.*,c.InverterName as INVERTERName,c.ID as ID FROM 
                                (
	                                SELECT MAX(aa.TIMESTAMP) AS maxtime ,aa.INVERTERID from (SELECT * from {site_db}.{site_table} ORDER BY ID desc LIMIT 1000) aa GROUP BY INVERTERID
                                ) a
                                LEFT JOIN 
                                (SELECT * from {site_db}.{site_table} ORDER BY ID desc LIMIT 1000) b ON a.maxtime = b.TIMESTAMP AND a.INVERTERID = b.INVERTERID 
                                LEFT JOIN {site_db}.inverter c ON b.INVERTERID = c.InverterId
                                WHERE b.INVERTERID in @ids
                                ";

                    result = (await conn.QueryAsync<InverterHistory>(sql, new { ids = post })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }


        public async Task<InverterDetailModal> GetInverterInfoModal(int Id, string Time, string DB, string Table)
        {
            InverterDetailModal result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT * FROM {DB}.inverter i 
                                    LEFT JOIN
                                    (SELECT * from {DB}.{Table} aa ORDER BY aa.ID desc LIMIT 1000) inv 
                                    ON i.InverterId = inv.INVERTERID WHERE inv.TIMESTAMP = '{Time}' and i.ID = {Id}
                                ";

                    result = await conn.QueryFirstOrDefaultAsync<InverterDetailModal>(sql);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<List<AreaSelectItemList>> GetApicallItemList(int powerStationId, string dbname)
        {
            List<AreaSelectItemList> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT 
                                    aa.Item AS VALUE, aa.ItemName AS `text` 
                                    FROM 
                                    (
	                                    SELECT api.Item, api.ItemName
	                                    FROM apicall api
	                                    LEFT join 
                                        (SELECT * FROM {dbname}.power_station_exception ex WHERE ex.Deleted = 0 AND ex.PowerStationId = {powerStationId}) a
	                                    ON a.`Type` = api.Item
	                                    WHERE api.PowerStationId = {powerStationId}
	                                    AND ISNULL(a.Id)
	                                    GROUP BY api.Item 
                                    ) aa
                                    ";

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

        public async Task<List<ApicallList>> GetApicallList(int PowerStationId, string Type)
        {
            List<ApicallList> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT * FROM apicall WHERE PowerStationId = {PowerStationId} and Item = '{Type}' order by LimitValue";

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

        public async Task<List<string>> GetShareDevicePowerstationName(int Id, string DBname)
        {
            List<string> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $@"SELECT ps.Name FROM {DBname}.sharedevice sh 
                                    LEFT JOIN power_station ps ON ps.Id = sh.PowerStationId
                                    WHERE sh.DeviceId IN 
                                    (SELECT Id FROM {DBname}.device WHERE PowerStationId = {Id}) group BY ps.Name";

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

        public async Task DropShareDevice(int powerstationId, string DBname)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = $"DELETE FROM {DBname}.sharedevice WHERE DeviceId IN (SELECT Id FROM {DBname}.device WHERE PowerStationId = {powerstationId} )";

                        await conn.ExecuteAsync(sql, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        public async Task DeleteALLPowerStationOperationPersonnel(int stationId)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = @$"UPDATE power_station_operation_personnel
                                        SET Deleted = 1
                                        WHERE PowerStationId = {stationId} ";

                        await conn.ExecuteAsync(sql, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        public async Task<List<string>> CheckStationStatus(string code, string DBname, string powerStationID)
        {
            List<string> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    List<PowerstationOption> devices = new List<PowerstationOption>
                    {
                        new PowerstationOption{Text="日照計",Value="PYR"},
                        new PowerstationOption{Text="模組溫度計",Value="MTR"},
                        new PowerstationOption{Text="累計日照計",Value="TPY"}
                    };
                    // devices.Add(new PowerstationOption { Text = "電表", Value = "PWR" });
                    var sql2 = "";
                    foreach (var device in devices)
                    {
                        //sql2 += @$"#檢查是否存在設備({device.Text})#
                        //    set @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                        //                        select ', siteID ,', ''device'', ''device_Type_{device.Value}'',
                        //           case when count(*) > 0 then 0 else 1 end isError,
                        //           now(),
                        //           case when count(*) > 0 then Null else ''電站無正常啟用{device.Text}'' end error_reason
                        //                        from {DBname}.device b 
                        //                        join power_station a on a.Id = b.PowerStationId
                        //                        where b.Deleted = 0 and b.Enabled = 1 and b.Status = 1 and b.Type = ''{device.Value}'' and a.`Code` = ', siteID );
                        //    prepare stmt from @qry1 ;
                        //    execute stmt ;";
                        sql2 += @$"#檢查是否存在設備({device.Text})#
                            set @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                                                select ', ''{code}01'' ,', ''device'', ''device_Type_{device.Value}'',
							                            case when count(*) > 0 then 0 else 1 end isError,
							                            now(),
							                            case when count(*) > 0 then Null else ''電站無正常啟用{device.Text}'' end error_reason
                                                from {DBname}.device b 
                                                left join {DBname}.sharedevice c on b.id = c.DeviceId  
                                                where (b.PowerStationId = {powerStationID} or c.PowerStationId = {powerStationID}) 
                                                        and b.Deleted = 0 and b.Enabled = 1 and b.Status = 1 and b.Type = ''{device.Value}'' );
                            prepare stmt from @qry1 ;
                            execute stmt ;";
                    }

                    List<string> tables = new List<string>
                    {
                        "inv",
                        "station",
                       // "sensor",
                        "sensoravg",
                    };
                    // tables.Add("meter");
                    var sql3 = "";
                    foreach (var table in tables)
                    {
                        sql3 += @$"# 檢查資料表_{table}是否存在#
                                set @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                                select ', ''{code}01'' ,', ''{table}'', ''{table}_Table'',
                						case when count(*) > 0 then 0 else 1 end isError,
                                        now(),
                						case when count(*) > 0 then Null else ''_{table}原始資料表不存在'' end error_reason
                                from information_schema.SCHEMATA,information_schema.TABLES
                                where SCHEMA_NAME = ''{DBname}'' AND Table_schema = ''{DBname}'' AND TABLE_NAME = ''s{code}01_{table}''');
                                prepare stmt from @qry1;
                                execute stmt;";
                    }



                    var sql = $@"DROP PROCEDURE IF EXISTS `sp_power_station_enable_check` ;
                               
                                CREATE PROCEDURE `sp_power_station_enable_check`( siteID varchar(20) )
                                BEGIN
                                declare _siteDB varchar(20);
                                declare _siteNo int(2);
    
                                SELECT SiteDB into _siteDB
                                from power_station where `code` = siteID;
   
                                #clear check result 
                                set @qry1:= concat('delete from power_station_enable_check where `siteID` = ', siteID );
                                prepare stmt from @qry1 ;
                                execute stmt ;                       
                                #檢查電站缺少的欄位(住址)#
	                                SET @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                                                    select ', ''{code}01'' ,', ''station'', ''address_isnull'', case when ISNULL(a.Address) = 0 then 0 else 1 end isError, now() ,case when ISNULL(a.Address) = 0 then Null else ''電站住址為空'' end error_reason
                                                    from power_station a 
                                                    where a.`Code` = ', ''{code}01'' );
                                prepare stmt from @qry1 ;
                                execute stmt ;  
    
	                            #檢查電站缺少的欄位(名稱)#
                            set @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                                                select ', ''{code}01'' ,', ''station'', ''name_isnull'', case when ISNULL(a.Name) = 0 then 0 else 1 end isError, now(),case when ISNULL(a.Name) = 0 then Null else ''電站名稱為空'' end error_reason
                                                from power_station a 
                                                where a.`Code` = ', ''{code}01'' );
                            prepare stmt from @qry1 ;
                            execute stmt ; 
	 
	                            #檢查電站缺少的欄位(編號)#
                            set @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                                                select ', ''{code}01'' ,', ''station'', ''code_isnull'', case when ISNULL(a.Code) = 0 then 0 else 1 end isError, now(),case when ISNULL(a.Code) = 0 then Null else ''電站編號為空'' end error_reason
                                                from power_station a 
                                                where a.`Code` = ', ''{code}01'' );
                            prepare stmt from @qry1 ;
                            execute stmt ; 
    
	                            #檢查電站缺少的欄位(裝置容量-不得為 0)#
                            set @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                                                select ', ''{code}01'' ,', ''station'', ''generatingCapacity_isnullorempty'', case when a.GeneratingCapacity > 0 and ISNULL(a.GeneratingCapacity) = 0 then 0 else 1 end isError, now(),case when a.GeneratingCapacity > 0 and ISNULL(a.GeneratingCapacity) = 0 then Null else ''裝置容量為 0 或 不存在'' end error_reason
                                                from power_station a 
                                                where a.`Code` = ', ''{code}01'' );
                            prepare stmt from @qry1 ;
                            execute stmt ;     
                           
    
                            #檢查電站缺少的欄位(座標)#
                            set @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                                                select ', '{code}01' ,', ''station'', ''coordinate_isnull'', case when ISNULL(a.Coordinate) = 0 then 0 else 1 end isError, now(),case when ISNULL(a.Coordinate) = 0 then Null else ''電站座標為空'' end error_reason
                                                from power_station a 
                                                where a.`Code` = ', '{code}01' );
                            prepare stmt from @qry1 ;
                            execute stmt ; 
    
                            #檢查電站歸屬公司狀態(刪除)#
                            set @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                                                select ', ''{code}01'' ,', ''company'', ''company_deleted'',
							                            case when b.Deleted = 0 then 0 else 1 end isError,
							                            now(),
							                            case when b.Deleted = 0 then Null else ''公司已被刪除'' end error_reason
                                                from power_station a 
                                                join company b on a.CompanyId = b.Id
                                                where a.`Code` = ', ''{code}01'' );
                            prepare stmt from @qry1 ;
                            execute stmt ;
    
                            #檢查電站歸屬公司狀態(凍結)#
                            set @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                                                select ', ''{code}01'' ,', ''company'', ''company_status'',
							                            case when b.Status = 1 then 0 else 1 end isError,
							                            now(),
							                            case when b.Status = 1 then Null else ''公司已被凍結'' end error_reason
                                                from power_station a 
                                                join company b on a.CompanyId = b.Id
                                                where a.`Code` = ', ''{code}01'' );
                            prepare stmt from @qry1 ;
                            execute stmt ;
    
                            #檢查電站歸屬公司狀態(存在)#
                            set @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                                                select ', ''{code}01'' ,', ''company'', ''company_isnull'',
							                            case when count(*) > 0 then 0 else 1 end isError,
							                            now(),
							                            case when count(*) > 0 then Null else ''公司不存在'' end error_reason
                                                from power_station a 
                                                join company b on a.CompanyId = b.Id
                                                where a.`Code` = ', ''{code}01'' );
                            prepare stmt from @qry1 ;
                            execute stmt ;

                            #檢查電站有無運維人員#
                            set @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                                                select ', ''{code}01'' ,', ''station'', ''operation_personnel_count'',
							                            case when count(*) > 0 then 0 else 1 end isError,
							                            now(),
							                            case when count(*) > 0 then Null else ''電站無運維人員'' end error_reason
                                                from power_station_operation_personnel b 
                                                join power_station a on a.Id = b.PowerStationId
                                                where b.Deleted = 0 and a.`Code` = ', ''{code}01'' );
                            prepare stmt from @qry1 ;
                            execute stmt ;
                            " + sql2 + $@"
                            #檢查設備DBName是否填寫#
                            set @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                                                select ', ''{code}01'' ,', ''device'', ''device_DBName'',
							                            case when count(*) > 0 then 1 else 0 end isError,
							                            now(),
							                            case when count(*) > 0 then ''有設備DBName欄位未填寫'' else Null end error_reason
                                                from {DBname}.device b 
                                                join power_station a on a.Id = b.PowerStationId
                                                where b.Deleted = 0 and b.Enabled = 1 and b.Status = 1 and b.DBName Is Null and a.`Code` = ', ''{code}01'' );
                            prepare stmt from @qry1 ;
                            execute stmt ;
    
                            #檢查設備TableName是否填寫#
                            set @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                                                select ', ''{code}01'' ,', ''device'', ''device_TableName'',
							                            case when count(*) > 0 then 1 else 0 end isError,
							                            now(),
							                            case when count(*) > 0 then ''有設備TableName欄位未填寫'' else Null end error_reason
                                                from {DBname}.device b 
                                                join power_station a on a.Id = b.PowerStationId
                                                where b.Deleted = 0 and b.Enabled = 1 and b.Status = 1 and b.TableName Is Null and a.`Code` = ', ''{code}01'' );
                            prepare stmt from @qry1 ;
                            execute stmt ;
    
                            #檢查設備ColName是否填寫#
                            set @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                                                select ', ''{code}01'' ,', ''device'', ''device_ColName'',
							                            case when count(*) > 0 then 1 else 0 end isError,
							                            now(),
							                            case when count(*) > 0 then ''有設備ColName欄位未填寫'' else Null end error_reason
                                                from {DBname}.device b 
                                                join power_station a on a.Id = b.PowerStationId
                                                where b.Deleted = 0 and b.Enabled = 1 and b.Status = 1 and b.ColName Is Null and a.`Code` = ', ''{code}01'' );
                            prepare stmt from @qry1 ;
                            execute stmt ;

                            " + sql3 + @$"
                            # 檢查是否有控制器#
                                            set @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                
                                                                select ', ''{code}01'' ,', ''controller'', ''controller_isnull'',
                							                            case when count(*) > 0 then 0 else 1 end isError,
                                                                        now(),
                							                            case when count(*) > 0 then Null else ''電站無控制器'' end error_reason
                                                from {DBname}.power_station a
                                                join {DBname}.controller b on a.id = b.PowerStationId
                                                where a.`Code` = ', ''{code}01'', ' and b.Deleted = 0' );
                            prepare stmt from @qry1;
                                            execute stmt;

                            # 檢查是否有逆變器#
                                            set @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                
                                                                select ', ''{code}01'' ,', ''inverter'', ''inverter_isnull'',
                							                            case when count(*) > 0 then 0 else 1 end isError,
                                                                        now(),
                							                            case when count(*) > 0 then Null else ''電站無逆變器'' end error_reason
                                                from {DBname}.power_station a
                                                join {DBname}.controller b on a.id = b.PowerStationId
                                                join {DBname}.inverter c on b.id = c.ControllerId
                                                where a.`Code` = ', ''{code}01'', ' and c.Deleted = 0 and c.Enabled = 1 and c.Status = 1' );
                            prepare stmt from @qry1;
                                            execute stmt;

                            # 回傳結果
                                            set @qry1:= concat('select error_reason  from power_station_enable_check  
                                                                where siteID = ', ''{code}01'' ,' and isError = 1'); 
                
                                            prepare stmt from @qry1 ;
                                            execute stmt;
                                            END ;
                                            

                                            call sp_power_station_enable_check('{code}'); ";
                    result = (await conn.QueryAsync<string>(sql)).ToList();

                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task<List<string>> CheckStationStatus_v2(string code, string DBname, string powerStationID)
        {
            List<string> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    List<PowerstationOption> devices = new List<PowerstationOption>
                    {
                        new PowerstationOption{Text="日照計",Value="PYR"},
                        new PowerstationOption{Text="模組溫度計",Value="MTR"},
                        new PowerstationOption{Text="累計日照計",Value="TPY"}
                    };
                    // devices.Add(new PowerstationOption { Text = "電表", Value = "PWR" });
                    // clear check result 
                    var sql = $@" delete from power_station_enable_check where `siteID` = '{code}' ";
                    await conn.ExecuteAsync(sql);

                    var sql2 = "";
                    foreach (var device in devices)
                    {
                        //sql2 += @$"#檢查是否存在設備({device.Text})#
                        //    set @qry1:= concat('insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                        //                        select ', siteID ,', ''device'', ''device_Type_{device.Value}'',
                        //           case when count(*) > 0 then 0 else 1 end isError,
                        //           now(),
                        //           case when count(*) > 0 then Null else ''電站無正常啟用{device.Text}'' end error_reason
                        //                        from {DBname}.device b 
                        //                        join power_station a on a.Id = b.PowerStationId
                        //                        where b.Deleted = 0 and b.Enabled = 1 and b.Status = 1 and b.Type = ''{device.Value}'' and a.`Code` = ', siteID );
                        //    prepare stmt from @qry1 ;
                        //    execute stmt ;";
                        //#檢查是否存在設備({device.Text})#
                        sql2 += @$"insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                                                select '{code}', 'device', 'device_Type_{device.Value}',
							                            case when count(*) > 0 then 0 else 1 end isError,
							                            now(),
							                            case when count(*) > 0 then Null else '電站無正常啟用{device.Text}' end error_reason
                                                from {DBname}.device b left join {DBname}.sharedevice c on b.id = c.DeviceId  
                                                where (b.PowerStationId = {powerStationID} or c.PowerStationId = {powerStationID}) 
                                                        and b.Deleted = 0 and b.Enabled = 1 and b.Status = 1 and b.Type = '{device.Value}' ; ";
                    }
                    await conn.ExecuteAsync(sql2);

                    List<string> tables = new List<string>
                    {
                        "inv",
                        "station",
                        "sensoravg",
                    };
                    // tables.Add("meter");
                    var sql3 = "";
                    //檢查資料表_{table}是否存在#
                    foreach (var table in tables)
                    {
                        sql3 += @$" insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                                select  '{code}', '{table}', '{table}_Table',
                						case when count(*) > 0 then 0 else 1 end isError,
                                        now(),
                						case when count(*) > 0 then Null else '_{table}原始資料表不存在' end error_reason
                                from information_schema.SCHEMATA,information_schema.TABLES
                                where SCHEMA_NAME = '{DBname}' AND Table_schema = '{DBname}' AND TABLE_NAME = 's{code}01_{table}';";
                    }
                    await conn.ExecuteAsync(sql3);

                   

                    //# 檢查電站缺少的欄位(住址)#
                    sql = $@"insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                              select '{code}' , 'station', 'address_isnull', case when ISNULL(a.Address) = 0 then 0 else 1 end isError, now() ,case when ISNULL(a.Address) = 0 then Null else '電站住址為空' end error_reason
                              from power_station a 
                              where a.`Code` = '{code}' ;";
                    

                    // # 檢查電站缺少的欄位(名稱)#
                    sql += $@"insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                              select '{code}' , 'station', 'name_isnull', 
                                    case when ISNULL(a.Name) = 0 then 0 else 1 end isError, now(), 
                                    case when ISNULL(a.Name) = 0 then Null else '電站名稱為空' end error_reason
                              from power_station a 
                              where a.`Code` = '{code}' ;";
                    await conn.ExecuteAsync(sql, commandTimeout: 600);

                    // # 檢查電站缺少的欄位(編號)#
                    sql = $@"insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                              select '{code}' , 'station', 'code_isnull', 
                                    case when ISNULL(a.Code) = 0 then 0 else 1 end isError, now(),
                                    case when ISNULL(a.Code) = 0 then Null else '電站編號為空' end error_reason
                              from power_station a 
                              where a.`Code` = '{code}' ;";


                    // #檢查電站缺少的欄位(裝置容量-不得為 0)#
                    sql += $@"insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                              select '{code}' , 'station', 'generatingCapacity_isnullorempty', 
                                    case when a.GeneratingCapacity > 0 and ISNULL(a.GeneratingCapacity) = 0 then 0 else 1 end isError, now(),
                                    case when a.GeneratingCapacity > 0 and ISNULL(a.GeneratingCapacity) = 0 then Null else '裝置容量為 0 或 不存在' end error_reason
                              from power_station a 
                              where a.`Code` = '{code}' ;";
                    
                    //# 檢查電站缺少的欄位(座標)#
                    sql += $@"insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                              select '{code}' , 'station', 'coordinate_isnull', 
                                   case when ISNULL(a.Coordinate) = 0 then 0 else 1 end isError, now(),
                                   case when ISNULL(a.Coordinate) = 0 then Null else '電站座標為空' end error_reason
                              from power_station a 
                              where a.`Code` = '{code}' ;";
                    await conn.ExecuteAsync(sql, commandTimeout: 600);

                    // #檢查電站歸屬公司狀態(刪除)#
                    sql = $@"insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                              select '{code}' , 'company', 'company_deleted', 
                                    case when b.Deleted = 0 then 0 else 1 end isError,
							        now(),
							        case when b.Deleted = 0 then Null else '公司已被刪除' end error_reason
                              from power_station a 
                              join company b on a.CompanyId = b.Id
                              where a.`Code` = '{code}' ;"; 


                    // #檢查電站歸屬公司狀態(凍結)#
                    sql += $@"insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                              select '{code}' , 'company', 'company_deleted', 
                                    case when b.Deleted = 0 then 0 else 1 end isError,
							        now(),
							        case when b.Deleted = 0 then Null else '公司已被刪除' end error_reason
                              from power_station a 
                              join company b on a.CompanyId = b.Id
                              where a.`Code` = '{code}' ;";


                    sql += $@"insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                              select '{code}' , 'company', 'company_status', 
                                    case when b.Status = 1 then 0 else 1 end isError,
							        now(),
							        case when b.Status = 1 then Null else '公司已被凍結' end error_reason
                              from power_station a 
                              join company b on a.CompanyId = b.Id
                              where a.`Code` = '{code}' ;";
                    await conn.ExecuteAsync(sql, commandTimeout: 600);

                    //      #檢查電站歸屬公司狀態(存在)#
                    sql = $@"insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                              select '{code}' , 'company', 'company_isnull', 
                                     case when count(*) > 0 then 0 else 1 end isError,
							         now(),
							         case when count(*) > 0 then Null else '公司不存在' end error_reason
                              from power_station a 
                              join company b on a.CompanyId = b.Id
                              where a.`Code` = '{code}' ;";

                    //       #檢查電站有無運維人員#
                    sql += $@"insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                              select '{code}' , 'station', 'operation_personnel_count', 
                                       case when count(*) > 0 then 0 else 1 end isError,
							           now(),
							           case when count(*) > 0 then Null else '電站無運維人員' end error_reason
                                from power_station_operation_personnel b 
                                join power_station a on a.Id = b.PowerStationId
                                where b.Deleted = 0 and a.`Code` = '{code}' ;";
                    await conn.ExecuteAsync(sql, commandTimeout: 600);

                    // #檢查設備DBName是否填寫#
                    sql = $@" insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                       select '{code}' , 'device', 'device_DBName',
					            case when count(*) > 0 then 1 else 0 end isError,
					            now(),
					            case when count(*) > 0 then '有設備DBName欄位未填寫' else Null end error_reason
                        from {DBname}.device b 
                        join power_station a on a.Id = b.PowerStationId
                        where b.Deleted = 0 and b.Enabled = 1 and b.Status = 1 and b.DBName Is Null and a.`Code` = '{code}' ;";

                    // #檢查設備TableName是否填寫#
                    sql += $@" insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                              select '{code}' , 'device', 'device_TableName',
							           case when count(*) > 0 then 1 else 0 end isError,
							           now(),
							           case when count(*) > 0 then '有設備TableName欄位未填寫' else Null end error_reason
                              from {DBname}.device b 
                              join power_station a on a.Id = b.PowerStationId
                              where b.Deleted = 0 and b.Enabled = 1 and b.Status = 1 and b.TableName Is Null and a.`Code` = '{code}' ";
                    await conn.ExecuteAsync(sql, commandTimeout: 600);

                    // #檢查設備ColName是否填寫#
                    sql = $@" insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                              select '{code}' , 'device', 'device_ColName',
							        case when count(*) > 0 then 1 else 0 end isError,
							        now(),
							        case when count(*) > 0 then '有設備ColName欄位未填寫' else Null end error_reason
                              from {DBname}.device b 
                              join power_station a on a.Id = b.PowerStationId
                              where b.Deleted = 0 and b.Enabled = 1 and b.Status = 1 and b.ColName Is Null and a.`Code` = '{code}' ;";
                     
                     //  # 檢查是否有控制器#
                     sql += $@" insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                              select '{code}' , 'controller', 'controller_isnull',
							        case when count(*) > 0 then 0 else 1 end isError,
							        now(),
							        case when count(*) > 0 then Null else '電站無控制器' end error_reason
                             from {DBname}.power_station a
                             join {DBname}.controller b on a.id = b.PowerStationId
                             where a.`Code` = '{code}'  and b.Deleted = 0 ;";

                    //  # 檢查是否有逆變器#
                    sql += $@" insert power_station_enable_check(siteID, check_type, check_item, isError, check_Date, error_reason)
                              select '{code}' , 'inverter', 'inverter_isnull',
							        case when count(*) > 0 then 0 else 1 end isError,
							        now(),
							        case when count(*) > 0 then Null else '電站無逆變器或未啟用' end error_reason
                           from {DBname}.power_station a
                           join {DBname}.controller b on a.id = b.PowerStationId
                           join {DBname}.inverter c on b.id = c.ControllerId
                           where a.`Code` = '{code}'  and c.Deleted = 0 and c.Enabled = 1 and c.Status > 0 ;";
                    await conn.ExecuteAsync(sql, commandTimeout: 600);

                    //       # 回傳結果
                    sql = $@" select error_reason  from power_station_enable_check  
                              where siteID =  '{code}'  and isError = 1;"; 
                    result = (await conn.QueryAsync<string>(sql)).ToList();

                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task StationStatus(int stationId, int status, string subDB = "")
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = @$"UPDATE {subDB}power_station
                                        SET Status = {status}
                                        WHERE Id = {stationId} ";

                        await conn.ExecuteAsync(sql, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        public async Task UpdateInvStatus(string siteDB, List<string> codes, List<string> inverterIds = null, byte status = 0)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {

                        var sql = $@"UPDATE {siteDB}.inverter SET Status = {status} WHERE Enabled = 1 AND Deleted = 0 ";

                        if(codes != null && codes.Count > 0)
                        {
                            sql += " AND LEFT(InverterId, 9) IN @Codes";
                        }

                        if(inverterIds != null && inverterIds.Count > 0)
                        {
                            sql += " AND InverterId IN @InverterIds";
                        }

                        await conn.ExecuteAsync(sql, new { Codes = codes, InverterIds = inverterIds }, trans);

                        trans.Commit();
                    }
                    catch (Exception exception)
                    {
                        trans.Rollback();
                        throw exception;
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }

        public async Task<List<InvStatusErr>> GetInvStatusErr(List<string> codes)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();

                var resule = new List<InvStatusErr>();
                try
                {

                    var sql = $@"select b.DBName AS SiteDB, site_id, INVERTERID 
                                from err_main a join v_company_inv b on a.errDevice = b.INVERTERID
                                where  site_id IN @Codes and sourceState = 1
                                group by  b.DBName, site_id, INVERTERID";
                    resule = (await conn.QueryAsync<InvStatusErr>(sql, new { Codes = codes })).ToList();

                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }

                return resule;
            }
        }

        public async Task<Check4table> Check4table(string code,string dbname)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();

                var resule = new Check4table();
                try
                {

                    var sql = $@"SELECT * FROM 
                                (SELECT count(*) ctAvg,      a.SITEID AS Avg FROM {dbname}.s{code}01_sensoravg a ORDER BY a.ID DESC LIMIT 1) a,
                                (SELECT count(*) ctInv_site, a.SITEID AS Inv_site,a.INVERTERID as Inv_inveter FROM {dbname}.s{code}01_inv a ORDER BY a.ID DESC LIMIT 1) b,
                                (SELECT count(*) ctStation,  a.SITEID AS Station FROM {dbname}.s{code}01_station a ORDER BY a.ID DESC LIMIT 1) c
                                ";
                    resule = await conn.QueryFirstOrDefaultAsync<Check4table>(sql, commandTimeout: 600);

                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }

                return resule;
            }
        }

        public async Task<int> CheckInvTableColumn (string dbname, string code)
        {

            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();

                var resule = 0;
                try
                {
                    var sql = $@"SELECT count(*) FROM information_schema.columns WHERE table_schema='{dbname}' AND table_name = 's{code}01_inv' AND column_name = 'CrdTime'";
                    resule = await conn.QueryFirstOrDefaultAsync<int>(sql);

                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }

                return resule;
            }
        }

        public async Task<int> CheckSensorAvgTableColumn(string dbname, string code)
        {

            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();

                var resule = 0;
                try
                {
                    var sql = $@"SELECT count(*) FROM information_schema.columns WHERE table_schema='{dbname}' AND table_name = 's{code}01_sensoravg' AND column_name = 'CrdTime'";
                    resule = await conn.QueryFirstOrDefaultAsync<int>(sql);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }

                return resule;
            }
        }

        public async Task<int> CheckStationTableColumn(string dbname, string code)
        {

            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();

                var resule = 0;
                try
                {
                    // var sql = $@"SHOW INDEX from '{dbname}'.s{code}01_station where column_name <> 'ID';";
                    var sql = $@"SELECT COUNT(1) index_count -- , TABLE_NAME, GROUP_CONCAT(DISTINCT(index_name) SEPARATOR ',\n ') indexes
                                FROM INFORMATION_SCHEMA.STATISTICS
                                WHERE TABLE_SCHEMA = '{dbname}' and table_name = 's{code}01_station'
                                      AND INDEX_NAME != 'primary'
                                GROUP BY TABLE_NAME ;";
                    resule = await conn.QueryFirstOrDefaultAsync<int>(sql);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }

                return resule;
            }
        }


        public async Task AlertColInvTableColumn(string dbname, string code)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();

                try
                {
                    var sql = $@"
                                ALTER TABLE  {dbname}.s{code}01_inv add column `insertTime` datetime Default CURRENT_TIMESTAMP;
                                ALTER TABLE  {dbname}.s{code}01_inv ADD COLUMN CrdTime datetime;
                                use {dbname};
			                    create trigger trg01_s{code}01_inv
			                    before insert on {dbname}.s{code}01_inv
			                    FOR EACH ROW
			                    begin 
				                    set new.CrdTime = FROM_UNIXTIME(new.`TIMESTAMP`/1000,'%Y-%m-%d %H:%i');
			                    end;
                                use solar_master;
                                
                                update {dbname}.s{code}01_inv set crdtime = FROM_UNIXTIME(`TIMESTAMP`/1000,'%Y-%m-%d %H:%i'); 
			
			                    CREATE INDEX IDX02_s{code}01 ON {dbname}.s{code}01_inv(Inverterid, CrdTime);";

                    await conn.ExecuteAsync(sql);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }

            }
        }

        public async Task AlertColSensoravgTableColumn(string dbname, string code)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();

                try
                {
                    var sql = $@"
                                ALTER TABLE {dbname}.s{code}01_sensoravg add column `insertTime` datetime Default CURRENT_TIMESTAMP;
                                ALTER TABLE  {dbname}.s{code}01_sensoravg ADD COLUMN CrdTime datetime;
			                    use {dbname};
			                    create trigger trg01_s{code}01_sensoravg
			                    before insert on {dbname}.s{code}01_sensoravg  
			                    FOR EACH ROW
			                    begin 
				                    set new.CrdTime = FROM_UNIXTIME(new.`TIMESTAMP`/1000,'%Y-%m-%d %H:%i');
			                    end;
			                    use solar_master;
			
			                    update {dbname}.s{code}01_sensoravg set crdtime = FROM_UNIXTIME(`TIMESTAMP`/1000,'%Y-%m-%d %H:%i');
			
			                    CREATE INDEX IDX{code}01_sensoravg ON {dbname}.s{code}01_sensoravg(CrdTime);";
                    await conn.ExecuteAsync(sql);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }

            }
        }

        public async Task AlertColStationTableColumn(string dbname, string code)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();

                try
                {
                    var sql = $@" CREATE INDEX idx_s{code}01_station_TIMESTAMP ON {dbname}.s{code}01_station (`TIMESTAMP` DESC);
                                 alter  table  {dbname}.s{code}01_station add column `insertTime` datetime Default CURRENT_TIMESTAMP;";
                    await conn.ExecuteAsync(sql);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }

            }
        }

        public async Task<string> CalcIrrDayHistoryPerTwoHour(string dateTime, int powerStationId)
        {
            string result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    string d1 = dateTime + ":00:00";
                    //string sql = $@" select  irrday - 
                    //                  (select irrday from sensor_history_hour where powerstationID = {powerStationId} and LEFT(`TIMESTAMP`, 13 ) = '{Convert.ToDateTime(d1).AddHours(-1).ToString("yyyy-MM-dd HH")}' limit 1) irrdayhour
                    //               from sensor_history_hour z
                    //               where powerstationID = {powerStationId} and LEFT(z.`TIMESTAMP`, 13 ) = '{dateTime}'  ";
                    string sql = $@" select  IrrDay
                                   from sensor_history_hour z
                                   where powerstationID = {powerStationId} and LEFT(z.`TIMESTAMP`, 13 ) = '{Convert.ToDateTime(d1).AddHours(-1).ToString("yyyy-MM-dd HH")}' ";
                    result = await conn.QueryFirstOrDefaultAsync<string>(sql, commandTimeout: 600);
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }
    }
}
