using Fuel.Core.Transactions.Dto;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using FuelServer.Core.Entity;
using System.Linq.Expressions;
using Fuel.Core.Models;
using System.Net;
using Fuel.Payment.Service.Pay;
using DFS.Core.Abstractions.View;
using Fuel.Core;
using System;
using System.Transactions;


namespace Fuel.Application.Service
{
    public class TransactionsService : ITransactionsService
    {
        private readonly EntityHelper _entityHelper;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IPayService _payService;
        public readonly IFreeSql _fsql;
        public TransactionsService(EntityHelper entityHelper, IHttpContextAccessor httpContextAccessor, IPayService payService, IFreeSql fsql)
        {
            _entityHelper = entityHelper;
            _httpContextAccessor = httpContextAccessor;
            _payService = payService;
            _fsql = fsql;
        }

        /// <summary>
        /// 创建订单
        /// </summary>
        /// <param name="uploadTransactions"></param>
        /// <returns></returns>
        public async Task<ServiceResponse> CreateTransactions(UploadTransactions uploadTransactions)
        {
            Guid Buid = HttpRequestReader.GetCurrentBuId(); //站点id
            string key = string.Empty;
            int OrderType = 0;//订单类型
            if (OrderType == 1)//预支付
            {
                key = uploadTransactions.ExternalGunNumber + ":" +
                         uploadTransactions.OriginalAmount + ":" +
                         uploadTransactions.Qty + ":" +
                         uploadTransactions.MiniProgramID + ":" +
                         Buid.ToString();
            }
            else//后支付
            {
                key = uploadTransactions.ExternalGunNumber + ":" +
                       uploadTransactions.OriginalAmount + ":" +
                       uploadTransactions.Qty + ":" +
                       uploadTransactions.MiniProgramID + ":" +
                       uploadTransactions.FuelItemTransactionEndTime + ":" +
                        uploadTransactions.TransactionNumber + ":" +
                       Buid.ToString();
            }
            transactions output = await GetRedisTransactions(uploadTransactions, key);
            if (output != null)
            {
                return ServiceResponse.Ok(output);
            }
            var _product = await _entityHelper.GetEntitiesAsync<product>(_ => _.Buid == Buid && _.ProductName == uploadTransactions.Product);
            if (_product.Count() <= 0)
            {
                return ServiceResponse.Error("油品查询失败，油品名称：" + uploadTransactions.Product);
            }
            var _nozzle = await _entityHelper.GetEntitiesAsync<nozzle>(_ => _.Buid == Buid && _.ExternalGunNumber == uploadTransactions.ExternalGunNumber);
            if (_nozzle.Count() <= 0)
            {
                return ServiceResponse.Error("油枪查询失败，油枪名称：" + uploadTransactions.ExternalGunNumber);
            }
            var trx = uploadTransactions.ToTransactions(uploadTransactions, Buid, _product.FirstOrDefault(), _nozzle.FirstOrDefault(), OrderType);
            //int affectedRows = _fsql.Insert<transactions>().AppendData(trx).ExecuteAffrows();
            // var affectedRows = _fsql.Insert<transactions>().AppendData(trx).ExecuteInserted();
            var id = _fsql.Insert(trx).ExecuteIdentity();
            if (id > 0)
            {
                var insertedTransaction = _fsql.Select<transactions>()
                    .Where(t => t.Id == id)
                    .First();
                string jsonString = JsonConvert.SerializeObject(insertedTransaction);

                RedisHelper.SetAsync(key, jsonString, 3600);
                return ServiceResponse.Ok(insertedTransaction);
            }
            else
            {
                return ServiceResponse.Error("订单信息插入失败");
            }
        }
        public async Task<ServiceResponse> GetTransactionsAsync(TransactionsInput input)
        {
            string Buid = _httpContextAccessor.HttpContext.Request.Headers["Buid"].FirstOrDefault();
            Guid guid = Guid.Parse(Buid);
            Expression<Func<transactions, bool>> where = p => p.Buid == guid;
            if (input.TransactionID != null)
            {
                where = CombineExpressions(where, p => p.Id == input.TransactionID);
            }
            if (input.type != null)
            {
                var status = (transactionsORDERSTATUS)input.type.Value;
                where = CombineExpressions(where, p => p.OrderStatus == status);
            }
            if (input.MiniProgramID != null)
            {
                where = CombineExpressions(where, p => p.MiniProgramID == input.MiniProgramID);
            }
            if (input.TransactionSTime != null)
            {
                where = CombineExpressions(where, p => p.TransactionTime >= input.TransactionSTime);
            }
            if (input.TransactionETime != null)
            {
                where = CombineExpressions(where, p => p.TransactionTime == input.TransactionETime);
            }
            if (!string.IsNullOrEmpty(input.Product))
            {
                where = CombineExpressions(where, p => p.ProductName == input.Product);
            }
            var result = await _entityHelper.GetEntitiesAsync<transactions>(where);
            return ServiceResponse.Ok(result);
        }
        /// <summary>
        /// 小程序查询未支付订单
        /// </summary>
        /// <returns></returns>
        public async Task<ServiceResponse> GetMiniProgramTransactionsUnpaidAsync(TransactionsInput input)
        {
            string Buid = _httpContextAccessor.HttpContext.Request.Headers["Buid"].FirstOrDefault();
            Guid guid = Guid.Parse(Buid);
            Expression<Func<transactions, bool>> where = p => p.Buid == guid;
            if (input.MiniProgramID == null)
            {
                return ServiceResponse.Error("用户id为空");
            }
            where = CombineExpressions(where, p => p.MiniProgramID == input.MiniProgramID && p.OrderStatus == transactionsORDERSTATUS.Unpaid);
            var result = await _entityHelper.GetEntitiesAsync<transactions>(where);
            return ServiceResponse.Ok(result);
        }

        /// <summary>
        /// 小程序用户根据抢号查询未支付订单
        /// </summary>
        /// <returns></returns>
        public async Task<ServiceResponse> GetMiniProgramTransactionsUnpaidNozzleAsync(TransactionsInput input)
        {
            string Buid = _httpContextAccessor.HttpContext.Request.Headers["Buid"].FirstOrDefault();
            Guid guid = Guid.Parse(Buid);
            Expression<Func<transactions, bool>> where = p => p.Buid == guid;
            if (input.MiniProgramID == null)
            {
                return ServiceResponse.Error("用户id为空");
            }
            where = CombineExpressions(where, p => p.NozzleId == input.NozzleId && p.OrderStatus == transactionsORDERSTATUS.Unpaid);
            var result = await _entityHelper.GetEntitiesAsync<transactions>(where);
            return ServiceResponse.Ok(result);
        }
        /// <summary>
        /// 小程序查询已支付订单
        /// </summary>
        /// <returns></returns>
        public async Task<ServiceResponse> GetMiniProgramTransactionsPaidAsync(TransactionsInput input)
        {
            string Buid = _httpContextAccessor.HttpContext.Request.Headers["Buid"].FirstOrDefault();
            Guid guid = Guid.Parse(Buid);
            Expression<Func<transactions, bool>> where = p => p.Buid == guid;
            if (input.MiniProgramID == null)
            {
                return ServiceResponse.Error("用户id为空");
            }
            where = CombineExpressions(where, p => p.MiniProgramID == input.MiniProgramID && p.OrderStatus == transactionsORDERSTATUS.Paid);
            var result = await _entityHelper.GetEntitiesAsync<transactions>(where);
            return ServiceResponse.Ok(result);
        }
        /// <summary>
        /// 提交支付
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<ServiceResponse> CommitPayment(int trxId, string AuthCode)
        {
            bool paymentOK = false;
            var trx = _entityHelper.GetEntitiesAsync<transactions>(_ => _.Id == trxId).Result.FirstOrDefault();
            if (trx == null)
            {
                return ServiceResponse.Error(HttpStatusCode.NotAcceptable, "未查询到订单！");
            }
            var paytype = _entityHelper.GetEntitiesAsync<paytype>(_ => _.Id == trx.PaymentMethod).Result.FirstOrDefault();
            string billNumber = SequenceNumber.Next();//订单编号
            trx.TransactionNumber = billNumber;
            decimal payDueAmount = (decimal)trx.OriginalAmount;
            string Channel = paytype.Channel;
            var serviceResult = await _payService.PerformElectronicProcess(AuthCode, payDueAmount, billNumber);
            Payment.Core.Models.ElectronicOrderProcessResultModel payResult = (Payment.Core.Models.ElectronicOrderProcessResultModel)serviceResult.Data;
            if (!serviceResult.IsSuccessful() || payResult.ResultCode == "PAY_ERROR")
            {
                return ServiceResponse.Error(HttpStatusCode.NotAcceptable, "支付失败");
            }
            trx.ActualPaymentAmount = payDueAmount;//实际支付金额
            trx.ResultCode = payResult?.ResultCode;//支付成功应该为0
            trx.ErrorDetail = payResult?.ErrorDetail;
            _entityHelper.UpdateAsync(trx);
            return ServiceResponse.Ok(trx);
        }
        /// <summary>
        /// 查询redis订单缓存
        /// </summary>
        /// <returns></returns>
        public async Task<transactions> GetRedisTransactions(UploadTransactions uploadTransactions, string key)
        {
            string Buid = _httpContextAccessor.HttpContext.Request.Headers["Buid"].FirstOrDefault();
            var respond = RedisHelper.GetAsync(key).Result;
            if (respond == null)
            {
                return null;
            }
            transactions transactions = JsonConvert.DeserializeObject<transactions>(respond);
            return transactions;
        }
        // 辅助方法：组合两个表达式
        private static Expression<Func<T, bool>> CombineExpressions<T>(Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
        {
            ParameterExpression param = expr1.Parameters[0];
            Expression body = Expression.AndAlso(expr1.Body, Expression.Invoke(expr2, param));
            return Expression.Lambda<Func<T, bool>>(body, param);
        }
        /// <summary>
        /// 退款
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<ServiceResponse> RefundTrx(int trxId,
            double longitude,
            double latitude)
        {
            string Buid = _httpContextAccessor.HttpContext.Request.Headers["Buid"].FirstOrDefault();
            Guid guid = Guid.Parse(Buid);
            var businessunitinfo = _entityHelper.GetEntitiesAsync<businessunitinfo>(_ => _.Buid == guid).Result.FirstOrDefault();
            if (businessunitinfo == null)
            {
                return ServiceResponse.Error(HttpStatusCode.NotAcceptable, "站点为空");
            }
            string[] parts = businessunitinfo.GpsCoordinates.Split(',');
            if (parts.Length == 2 &&
           double.TryParse(parts[0], out double latitude2) &&
           double.TryParse(parts[1], out double longitude2))
            {

            }
            else
            {
                return ServiceResponse.Error(HttpStatusCode.NotAcceptable, "站点经纬度获取失败");
            }
            //计算调用方和油站的距离，超过距离判定为恶意请求
            double distance = DistanceCalculator.CalculateDistance(longitude, latitude, longitude2, latitude2);
            if (distance > 5)
            {
                return ServiceResponse.Error(HttpStatusCode.NotAcceptable, "该请求大于油站地址5公里");
            }

            var trx = _entityHelper.GetEntitiesAsync<transactions>(_ => _.Id == trxId).Result.FirstOrDefault();
            if (trx == null)
            {
                return ServiceResponse.Error(HttpStatusCode.NotAcceptable, "未查询到订单！");
            }
            else if (trx.OrderStatus == transactionsORDERSTATUS.FullyRefunded)
            {
                return ServiceResponse.Error(HttpStatusCode.NotAcceptable, "该订单已退款");
            }
            else if (trx.OrderStatus == transactionsORDERSTATUS.PartiallyRefunded)
            {
                return ServiceResponse.Error(HttpStatusCode.NotAcceptable, "该订单已部分退款");
            }
            else if (trx.OrderStatus == transactionsORDERSTATUS.Unpaid)
            {
                return ServiceResponse.Error(HttpStatusCode.NotAcceptable, "该订单未支付");
            }
            else if (trx.OrderStatus == transactionsORDERSTATUS.Unpaid)
            {
                return ServiceResponse.Error(HttpStatusCode.NotAcceptable, "该订单未支付");
            }
            //获取单价
            decimal? ProductPrice = _entityHelper.GetEntitiesAsync<product>(_ => _.Id == trx.ProductId).Result.FirstOrDefault().ProductPrice;
            if (ProductPrice == null)
            {
                return ServiceResponse.Error(HttpStatusCode.NotAcceptable, "单价获取失败");
            }
            //计算退款金额
            decimal RefundAmount = (decimal)((trx.Qty - trx.OriginalQty) * ProductPrice.Value);
            if (RefundAmount <= 0.0M)
            {
                return ServiceResponse.Error(HttpStatusCode.NotAcceptable, "该笔单无需退款");
            }
            //退款
            var serviceResult = await _payService.ReturnProcess(RefundAmount, "ALL_IN_SCAN", trx.TransactionNumber);
            Payment.Core.Models.ElectronicOrderProcessResultModel payResult = (Payment.Core.Models.ElectronicOrderProcessResultModel)serviceResult.Data;
            if (!serviceResult.IsSuccessful() || payResult.ResultCode == "PAY_ERROR")
            {
                return ServiceResponse.Error(HttpStatusCode.NotAcceptable, "退款失败");
            }

            trx.RefundAmount = RefundAmount;
            _entityHelper.UpdateAsync(trx);
            return ServiceResponse.Ok(trx);
        }
        public async Task<ServiceResponse> UnifiedOrder(int trxId)
        {
            var trx = _entityHelper.GetEntitiesAsync<transactions>(_ => _.Id == trxId).Result.FirstOrDefault();
            if (trx == null)
            {
                return ServiceResponse.Error(HttpStatusCode.NotAcceptable, "未查询到订单！");
            }
            var serviceResult = await _payService.UnifiedOrder((decimal)trx.OriginalAmount, "ALL_IN_SCAN");
            if (!serviceResult.IsSuccessful())
            {
                return ServiceResponse.Error(HttpStatusCode.NotAcceptable, "统一下单失败");
            }
            return ServiceResponse.Ok(serviceResult.Data);
        }
        public async Task<ServiceResponse> Redeem(int trxId, decimal OriginalQty)
        {
            var trx = _entityHelper.GetEntitiesAsync<transactions>(_ => _.Id == trxId).Result.FirstOrDefault();
            if (trx == null)
            {
                return ServiceResponse.Error(HttpStatusCode.NotAcceptable, "未查询到订单！");
            }
            trx.OriginalQty = OriginalQty;
            _entityHelper.UpdateAsync(trx);
            return ServiceResponse.Ok(trx);
        }
    }
}
