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

namespace SolarPower.Repository.Implement
{
    public class UserRepository : RepositoryBase<User>, IUserRepository
    {
        public UserRepository(IDatabaseHelper databaseHelper) : base(databaseHelper)
        {
            tableName = "user";
        }

        /// <summary>
        /// 透過Account，取得單一筆資料
        /// </summary>
        /// <param name="account"></param>
        /// <returns></returns>
        public async Task<User> GetOneByAccountAsync(string account)
        {
            User result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $"SELECT * FROM `{tableName}` WHERE deleted = 0 AND status = @Status AND account = @Account";

                    result = await conn.QueryFirstOrDefaultAsync<User>(sql, new { Status = UserStatusEnum.Normal, Account = account });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        /// <summary>
        /// 透過Email，取得單一筆資料
        /// </summary>
        /// <param name="email"></param>
        /// <returns></returns>
        public async Task<User> GetOneByEmailAsync(string email)
        {
            User result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    var sql = $"SELECT * FROM `{tableName}` WHERE deleted = 0 AND status = @Status AND email = @Email";

                    result = await conn.QueryFirstOrDefaultAsync<User>(sql, new { Status = UserStatusEnum.Normal, Email = email });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        /// <summary>
        /// 更換密碼
        /// </summary>
        /// <param name="password"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task ChangePassword(string password, int id)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = $"UPDATE `{tableName}` SET password = @Password WHERE id = @Id";

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

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

        /// <summary>
        /// 取得狀態為正常的使用者基本資料
        /// </summary>
        /// <param name="account"></param>
        /// <returns></returns>
        public MyUser GetMyUserInfoByAccount(string account)
        {
            MyUser result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    var sql = $"SELECT * FROM `{tableName}` WHERE deleted = 0 AND status = @Status AND account = @Account";

                    result = conn.QueryFirstOrDefault<MyUser>(sql, new { Status = UserStatusEnum.Normal, Account = account });
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                finally
                {
                    conn.Close();
                }
                return result;
            }
        }

        /// <summary>
        /// 取得使用者基本資料
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<SimpleUser> GetOneSimpleUser(int id)
        {
            SimpleUser result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                try
                {
                    var sql = @$"SELECT 
                                    u.*,
                                    c.Name AS CompanyName
                                FROM `{tableName}` u
                                LEFT JOIN company c ON u.CompanyId = c.Id
                                WHERE u.Deleted = 0 AND u.Id = @Id";

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

        /// <summary>
        /// 修改個人資料
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task UpdatePersonInfo(UpdateUser entity, List<string> properties)
        {

            GetProperties = typeof(UpdateUser).GetProperties();
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = GenerateUpdateQuery(properties);

                        await conn.ExecuteAsync(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>
        /// <returns></returns>
        public async Task UpdatePassword(UpdatePassword entity, List<string> properties)
        {
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                conn.Open();
                using (var trans = conn.BeginTransaction())
                {
                    try
                    {
                        var sql = GenerateUpdateQuery(properties);

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

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

        /// <summary>
        /// 透過搜尋條件，查詢所有使用者
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public async Task<List<UserDateTable>> GetAllByFilterAsync(PostUserFilter filter)
        {
            List<UserDateTable> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT
                                    u.*,
                                    c.Name AS CompanyName,
                                    r.Name AS RoleName,
                                    opc.SPStationAmount
                                    FROM `{tableName}` u
                                    LEFT JOIN company c ON u.CompanyId = c.Id
                                    LEFT JOIN `role` r ON u.RoleId = r.Id
                                    LEFT JOIN (SELECT op.UserId, COUNT(*) AS SPStationAmount FROM power_station_operation_personnel op WHERE op.Deleted = 0 GROUP BY op.UserId) opc ON u.Id = opc.UserId
                                    WHERE u.Deleted = 0";

                    if (filter.SelectedCompanyId > 0)
                    {
                        sql += @" AND u.CompanyId = @SelectedCompanyId";
                    }

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

                    if (filter.SelectedRoleId > 0)
                    {
                        sql += @" AND u.RoleId = @SelectedRoleId";
                    }

                    result = (await conn.QueryAsync<UserDateTable>(sql, filter)).ToList();

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


        /// <summary>
        /// 透過公司，查詢使用者列表,0為全部公司的所有人
        /// </summary>
        /// <param name="CompanyId"></param>
        /// <returns></returns>
        public async Task<List<UserSelectItemList>> GetUserSelectOptionListAsync(int companyId)
        {
            List<UserSelectItemList> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = $"SELECT Id AS Value, Name AS Text FROM `{tableName}` WHERE Deleted = 0";
                    if (companyId != 0)
                    {
                        sql += @" AND CompanyId=@companyId";
                    }
                    result = (await conn.QueryAsync<UserSelectItemList>(sql, new { companyId = companyId })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        /// <summary>
        /// 透過使用者Id，取得該使用者所有管理的電站
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<List<UserPowerStation>> GetUserPowerStationAsync(int userId)
        {
            List<UserPowerStation> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT 
                                    op.Id,
                                    ps.Code,
                                    ps.Name AS PowerStationName,
                                    CASE ps.IsEscrow WHEN 1 THEN CONCAT(ps.EscrowName, '(代管)')
                                                     WHEN 0 THEN c.Name
                                    END AS EscrowName
                                FROM power_station_operation_personnel op
                                LEFT JOIN power_station ps ON op.PowerStationId = ps.Id
                                LEFT JOIN company c ON ps.CompanyId = c.Id
                                WHERE op.Deleted = 0 AND op.UserId = @UserId";

                    result = (await conn.QueryAsync<UserPowerStation>(sql, new { UserId = userId })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }

        /// <summary>
        /// 透過Id，取得該使用者單一管理的電站
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<UserPowerStation> GetOneUserPowerStationAsync(int id)
        {
            UserPowerStation result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT 
                                    op.Id,
                                    ps.Code,
                                    ps.Name,
                                    CASE ps.IsEscrow WHEN 1 THEN CONCAT(ps.EscrowName, '(代管)')
                                                     WHEN 0 THEN c.Name
                                    END AS EscrowName
                                FROM power_station_operation_personnel op
                                LEFT JOIN power_station ps ON op.PowerStationId = ps.Id
                                LEFT JOIN company c ON ps.CompanyId = c.Id
                                WHERE op.Deleted = 0 AND op.Id = @Id";

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

        /// <summary>
        /// 透過編號，軟刪除使用者電站
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task DeleteOneUserPowerStationAsync(int id)
        {
            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 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<UserPowerStation>> GetCompanyPowerStationAsync(int companyId, int userId)
        {
            List<UserPowerStation> result;
            using (IDbConnection conn = this._databaseHelper.GetConnection())
            {
                try
                {
                    var sql = @$"SELECT
                                  ps.Id,
                                  ps.Code,
                                  ps.Name  AS PowerStationName,
                                  CASE ps.IsEscrow WHEN 1 THEN CONCAT(ps.EscrowName, '(代管)')
                                                   WHEN 0 THEN c.Name
                                  END AS EscrowName 
                                  FROM power_station ps 
                                  LEFT JOIN company c ON ps.CompanyId = c.Id
                                  WHERE ps.CompanyId = @CompanyId AND ps.Id NOT IN (SELECT psop.PowerStationId FROM power_station_operation_personnel psop WHERE psop.UserId = @UserId AND psop.Deleted = 0)";

                    result = (await conn.QueryAsync<UserPowerStation>(sql, new { CompanyId = companyId, UserId = userId })).ToList();
                }
                catch (Exception exception)
                {
                    throw exception;
                }
                return result;
            }
        }
    }
}
