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

namespace SolarPower.Repository.Implement
{
    public class OperationRepository : RepositoryBase<Operation>, IOperationRepository
    {
        public OperationRepository(IDatabaseHelper databaseHelper) : base(databaseHelper)
        {
            tableName = "operation_plan_create";
        }
        public async Task<List<PowerStationIdList>> GetPowerStationIdList(int UserId)
        {
            List<PowerStationIdList> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT tn.Id AS Value, tn.Name AS Text FROM power_station tn LEFT JOIN power_station_operation_personnel pp 
                                ON tn.Id=pp.PowerStationId
                                WHERE pp.UserId = @userid";
                    result = (await conn.QueryAsync<PowerStationIdList>(sql, new { userid = UserId })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task AddOperationPlan(OperationCreatePlan OperationPlan, List<string> properties)
        {
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    string sql = GenerateInsertQuery(properties);

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

            }
        }
        public async Task<List<OperationPlanTable>> OperationPlanTable(List<int> id, int Type)
        {
            List<OperationPlanTable> result = new List<OperationPlanTable>();
            var count = 0;

            string Wheresql = "";
            if (id.Count() <= 0)
            {
                return result;
            }
            //if (id.Count > 0)
            //{
            //    foreach (int too in id)
            //    {

            //        if (count == id.Count - 1)
            //        {
            //            Wheresql += too.ToString();
            //        }
            //        else
            //        {
            //            Wheresql += too.ToString() + " OR oc.PowerStationId = ";
            //        }
            //        count++;
            //    }

            //}
            //else
            //{
            //    Wheresql += "0";
            //}


            if (id.Count() > 0)
            {
                var temp_sql = string.Join(',', id);
                Wheresql = $"oc.PowerStationId IN ({temp_sql}) ";
            }

            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = "";
                    if (Type != 9)
                    {
                        sql = @$"SELECT oc.Id,oc.PlanId,oc.PowerStationId,oc.Type,
                                    oc.ScheduleNum,oc.ScheduleType,oc.WorkDay,oc.StartTime,
                                    oc.EmailType,oc.Description,oc.CreatedAt,ps.Name AS PowerStationName ,us.Name AS CreatedPerson FROM operation_plan_create oc LEFT JOIN power_station ps 
                                    ON oc.PowerStationId = ps.Id LEFT JOIN user us 
                                    ON us.Id = oc.CreatedBy WHERE ({Wheresql}) AND oc.Deleted = 0 AND oc.Type = {Type} ORDER BY CreatedAt DESC";
                    }
                    else
                    {
                        sql = @$"SELECT oc.Id,oc.PlanId,oc.PowerStationId,oc.Type,
                                    oc.ScheduleNum,oc.ScheduleType,oc.WorkDay,oc.StartTime,
                                    oc.EmailType,oc.Description,oc.CreatedAt,ps.Name AS PowerStationName ,us.Name AS CreatedPerson FROM operation_plan_create oc LEFT JOIN power_station ps 
                                    ON oc.PowerStationId = ps.Id LEFT JOIN user us 
                                    ON us.Id = oc.CreatedBy WHERE ({Wheresql}) AND oc.Deleted = 0 ORDER BY CreatedAt DESC";
                    }


                    result = (await conn.QueryAsync<OperationPlanTable>(sql)).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }
        public async Task<OperationCreatePlan> GetOneOperation(int id)
        {
            OperationCreatePlan result;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    var sql = @"SELECT * FROM operation_plan_create WHERE Deleted =0 AND Id = @Id";

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

                return result;
            }
        }

        public async Task UpdateOperationPlan(OperationCreatePlan OperationPlan, List<string> properties)
        {
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                var trans = conn.BeginTransaction();
                try
                {
                    var sql = GenerateUpdateQuery(properties);
                    await conn.ExecuteAsync(sql, OperationPlan, trans);

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

            }
        }

        public async Task AddToRecord(PlanToRecord record, List<string> properties2)
        {
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                var trans = conn.BeginTransaction();
                try
                {
                    string sql = GenerateInsertQueryWithCustomTable(properties2, "operation_record");
                    await conn.ExecuteAsync(sql, record);
                    trans.Commit();
                }
                catch (Exception exception)
                {
                    trans.Rollback();
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }

            }
        }

        /// <summary>
        /// 透過搜尋條件，查詢過濾後的運維作業記錄
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public async Task<List<OperationRecordDataTable>> GetAllRecordByFilterAsync(PostOperationRecordFilter filter)
        {
            List<OperationRecordDataTable> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    string where = "";
                    if (filter.Status == 2)
                    {
                        where = $"opr.Deleted = 1 ";
                    }
                    else
                    {
                        where = $"opr.Deleted = 0 AND opr.Status = {filter.Status} ";
                    }


                    var sql = @$"SELECT aa.* FROM ( 
                                    SELECT
                                        opr.*,
                                        ps.Name AS PowerStationName
                                    FROM operation_record opr
                                    LEFT JOIN power_station ps ON opr.PowerStationId = ps.Id
                                    WHERE {where} 
                                    AND ps.Id IN @PowerStationIds";

                    if (!string.IsNullOrEmpty(filter.Range))
                    {
                        filter.StartTime = filter.Range.Split('-')[0];
                        filter.EndTime = filter.Range.Split('-')[1];

                        sql += " AND opr.StartTime <= @EndDate";
                        sql += " AND opr.EndTime >= @StartDate";
                    }

                    if (filter.WorkType > 0)
                    {
                        filter.WorkType -= 1;
                        sql += @" AND opr.WorkType = @WorkType";
                    }
                    else
                    {
                        sql += @" AND opr.WorkType IN (0, 1)";
                        sql += @" UNION";
                        sql += @$" SELECT
                                opr.*,
                                ps.Name AS PowerStationName
                                FROM operation_record opr
                                LEFT JOIN power_station ps ON opr.PowerStationId = ps.Id
                                WHERE {where} 
                                AND ps.Id IN @PowerStationIds
                                AND opr.WorkType = 2";
                        if (!string.IsNullOrEmpty(filter.Range))
                        {
                            filter.StartTime = filter.Range.Split('-')[0];
                            filter.EndTime = filter.Range.Split('-')[1];

                            sql += " AND opr.StartTime <= @EndDate";
                            sql += " AND opr.EndTime >= @StartDate";
                        }
                        else
                        {
                            var today = DateTime.Now.ToString("yyyy-MM-dd");
                            var dateLimit = DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd");

                            sql += $" AND opr.CreatedAt BETWEEN '{dateLimit} 00:00:00' AND '{today} 23:59:59'";

                            //sql += $" AND opr.StartTime <= {today}";
                            //sql += $" AND opr.EndTime >= {dateLimit}";
                        }
                    }

                    sql += " ) aa ORDER BY aa.CreatedAt DESC";

                    result = (await conn.QueryAsync<OperationRecordDataTable>(sql,
                            new
                            {
                                PowerStationIds = filter.PowerStationIds,
                                WorkType = filter.WorkType,
                                StartDate = filter.StartTime,
                                EndDate = filter.EndTime
                            })).ToList();

                    if (result != null && result.Count > 0)
                    {


                        var sql_file = "SELECT * FROM operation_record_file WHERE Deleted = 0 AND RecordId = @RecordId";
                        foreach (var x in result)
                        {
                            x.RecordFiles = (await conn.QueryAsync<OperationRecordFile>(sql_file, new { RecordId = x.Id })).ToList();
                        }

                        var sql_WorkPersonId = @"SELECT GROUP_CONCAT(DISTINCT u.`Name` SEPARATOR ', ')
	                                                FROM operation_record_personnel op
	                                                LEFT JOIN user u ON u.deleted = 0 AND op.UserId = u.Id
	                                                WHERE op.Deleted = 0 AND op.OperationRecordId = @RecordId
	                                                GROUP BY op.OperationRecordId ";
                        foreach (var x in result)
                        {
                            x.WorkPersonName = await conn.QueryFirstOrDefaultAsync<string>(sql_WorkPersonId, new { RecordId = x.Id });
                        }
                    }
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        /// <summary>
        /// 透過Id，取得單一筆運維作業記錄
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<OperationRecord> GetOneOperationRecordAsync(int id)
        {
            OperationRecord result;

            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    var sql = @$"SELECT opr.*, ps.Name AS PowerStationName
                                FROM operation_record opr 
                                LEFT JOIN power_station ps ON opr.PowerStationId = ps.Id
                                WHERE opr.Deleted = 0 AND opr.Id = @Id";

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

                    if (result != null)
                    {
                        //取得圖片 or 檔案
                        var sql_file = @"SELECT * FROM operation_record_file WHERE Deleted = 0 AND RecordId = @RecordId";

                        result.RecordFiles = (await conn.QueryAsync<OperationRecordFile>(sql_file, new { RecordId = result.Id })).ToList();

                        //取得負責人員
                        var sql_operation_record_personnel = @"SELECT UserId FROM operation_record_personnel WHERE Deleted = 0 AND OperationRecordId = @OperationRecordId";

                        result.WorkPersonIds = (await conn.QueryAsync<int>(sql_operation_record_personnel, new { OperationRecordId = result.Id })).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> AddOneOperationRecordAsync(OperationRecord entity, List<string> properties)
        {
            var id = 0;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        string sql = GenerateInsertQueryWithCustomTable(properties, "operation_record");

                        sql += "SELECT LAST_INSERT_ID();";

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

                        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 UpdateOperationRecordAsync(UpdateOperationRecord entity, List<string> properties)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = GenerateUpdateQueryWithCustomTable(properties, "operation_record");
                        await conn.ExecuteAsync(sql, entity, trans);

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

        public async Task DeleteOneOperationRecordAsync(int id)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = $"UPDATE operation_record 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 ReductionOneOperationRecordAsync(int id)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = $"UPDATE operation_record SET deleted = 0 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="entity"></param>
        /// <param name="properties"></param>
        /// <returns></returns>
        public async Task<int> AddOperationRecordFilesAsync(List<OperationRecordFile> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    string sql = GenerateInsertQueryWithCustomTable(properties, "operation_record_file");

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

                return count;
            }
        }

        /// <summary>
        /// 透過Id，取得單一運維作業記錄檔案
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<OperationRecordFile> GetOneOperationRecordFileAsync(int id)
        {
            OperationRecordFile result;

            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    var sql = @$"SELECT *
                                FROM operation_record_file
                                WHERE Deleted = 0 AND Id = @Id";

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

        /// <summary>
        /// 透過Id，軟刪除運維作業記錄檔案
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task DeleteOneOperationRecordFile(int id)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = $"UPDATE operation_record_file 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<OperationCreatePlan>> GetOperationSchedules()
        {
            List<OperationCreatePlan> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT opc.*,ps.Name AS PowerStationName FROM operation_plan_create opc 
                                LEFT JOIN power_station ps ON opc.PowerStationId = ps.Id
                                WHERE opc.Deleted = 0";
                    result = (await conn.QueryAsync<OperationCreatePlan>(sql)).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }


        public async Task<List<MyUser>> GetOperationPersonnel(int PowerStationId)
        {
            List<MyUser> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT us.* FROM power_station_operation_personnel ps LEFT JOIN user us ON ps.UserId = us.Id WHERE ps.PowerStationId = {PowerStationId} and ps.Deleted = 0 AND us.Deleted = 0";
                    result = (await conn.QueryAsync<MyUser>(sql)).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        public async Task InsertNoticeSchedule(List<MyUser> personal, string Title, string content, int emailType)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        List<string> value = new List<string>();
                        foreach (MyUser a in personal)
                        {
                            if (IsValidEmail(a.Email))
                            {
                                value.Add($@"(1,'{a.Name}','{a.Email}','{Title}','{content}',{a.Id}, {emailType})");
                            }
                        }
                        string values = string.Join(",", value.ToArray());
                        if (value.Count > 0)
                        {
                            var sql = $"INSERT INTO `notice_schedule` (`Type`, `RecipientName`, `RecipientEmail`, `Subject`, `Content`,`UserId`,`EmailType`) VALUES {values};";

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

        public async Task AddOperationRecordPersonnelAsync(List<OperationRecordPersonnel> entity, List<string> properties)
        {
            int count;
            using (IDbConnection conn = _databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    string sql = GenerateInsertQueryWithCustomTable(properties, "operation_record_personnel");

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

                //return count;
            }
        }

        public async Task<List<int>> GetOperationRecordPersonnelIdsByOperationRecordId(int operationRecordId)
        {
            List<int> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    var sql = @$"SELECT UserId FROM operation_record_personnel WHERE Deleted = 0 AND OperationRecordId = @OperationRecordId";

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

        public async Task DeleteOperationRecordPersonnel(List<OperationRecordPersonnel> operationPersonnels)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = $"UPDATE operation_record_personnel SET Deleted = 1 WHERE OperationRecordId = @OperationRecordId AND UserId = @UserId";

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

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

        public async Task DeleteRecord(List<int> operations)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = $"UPDATE operation_record SET Deleted = 2 WHERE Id IN @Ids";

                        await conn.ExecuteAsync(sql, new { Ids = operations }, trans);

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

        public async Task<List<MyUser>> GetAllOperations()
        {
            List<MyUser> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT DISTINCT us.* 
				                    FROM power_station_operation_personnel ps 
				                    LEFT JOIN user us ON ps.UserId = us.Id 
				                    WHERE ps.Deleted = 0 AND us.Deleted = 0";
                    result = (await conn.QueryAsync<MyUser>(sql)).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        bool IsValidEmail(string strIn)
        {
            // Return true if strIn is in valid e-mail format.
            return Regex.IsMatch(strIn, @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");
        }

    }
}
