using BBWY.Client.APIServices;
using BBWY.Client.Extensions;
using BBWY.Client.Models;
using BBWY.Common.Models;
using GalaSoft.MvvmLight.Command;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using BBWY.Common.Extensions;
using BBWY.Client.Views.FinancialTerminal;
using Newtonsoft.Json;

namespace BBWY.Client.ViewModels
{
    public class ProcurementAuditViewModel : BaseVM, IDenpendency
    {
        private GlobalContext globalContext;
        private AuditFile selectAuditFile;
        private bool isLoading;
        private bool isAudited;
        private bool isShowPayBillPanel;
        private bool onlyException;
        private PurchaseOrderService purchaseOrderService;
        private FinancialTerminalService financialTerminalService;
        private DateTime startDate;
        private DateTime endDate;
        private Shop selectResultShop;
        private bool noMatchPurchaseOrder;
        private bool noChooseFundType;
        private string searchResultPurchaseOrder;
        private Platform? selectPurchasePlatform;

        public DateTime StartDate { get => startDate; set { Set(ref startDate, value); } }
        public DateTime EndDate { get => endDate; set { Set(ref endDate, value); } }

        public IList<AuditFile> AuditFileList { get; set; }

        public IList<AuditPayBill> AuditPayBillList { get; set; }

        public IList<Department> DepartmentList { get; set; }

        public IList<Shop> ShopList { get; set; }

        public IList<AuditPayBill> ShowAuditPayBillList { get; set; }

        public AuditFile SelectAuditFile
        {
            get => selectAuditFile; set
            {
                if (Set(ref selectAuditFile, value))
                    SearchLocal();
            }
        }

        public bool IsLoading { get => isLoading; set { Set(ref isLoading, value); } }
        public bool IsAudited { get => isAudited; set { Set(ref isAudited, value); } }

        public bool IsShowPayBillPanel
        {
            get => isShowPayBillPanel; set
            {
                Set(ref isShowPayBillPanel, value);
            }
        }

        public bool OnlyException
        {
            get => onlyException; set { Set(ref onlyException, value); }
        }

        public ICommand AuditCommand { get; set; }

        public ICommand ClearAuditCommand { get; set; }

        public ICommand ImportAliPayBillCommand { get; set; }

        public ICommand Import1688PurchaseOrderCommand { get; set; }

        public ICommand ImportJDShopOrderCommand { get; set; }

        public ICommand SearchHistoryCommand { get; set; }

        public ICommand SearchLocalCommand { get; set; }
        public ICommand ClearLocalConditionCommand { get; set; }

        public ICommand SaveCommand { get; set; }

        public ICommand ExportCommand { get; set; }

        public ICommand ShowAuditCapitalTypeInputModeCommand { get; set; }

        public ICommand HideAuditCapitalTypeInputModeCommand { get; set; }

        public Shop SelectResultShop { get => selectResultShop; set { Set(ref selectResultShop, value); } }

        public bool NoMatchPurchaseOrder { get => noMatchPurchaseOrder; set { Set(ref noMatchPurchaseOrder, value); } }
        public bool NoChooseFundType { get => noChooseFundType; set { Set(ref noChooseFundType, value); } }

        public string SearchResultPurchaseOrder { get => searchResultPurchaseOrder; set { Set(ref searchResultPurchaseOrder, value); } }

        public Platform? SelectPurchasePlatform { get => selectPurchasePlatform; set { Set(ref selectPurchasePlatform, value); } }

        public ProcurementAuditViewModel(PurchaseOrderService purchaseOrderService, FinancialTerminalService financialTerminalService, GlobalContext globalContext)
        {
            this.globalContext = globalContext;
            AuditFileList = new ObservableCollection<AuditFile>();
            AuditCommand = new RelayCommand(Audit);
            ClearAuditCommand = new RelayCommand(ClearAudit);
            ImportAliPayBillCommand = new RelayCommand(ImportAliPayBill);
            SearchHistoryCommand = new RelayCommand(SearchHistory);
            SearchLocalCommand = new RelayCommand(SearchLocal);
            ClearLocalConditionCommand = new RelayCommand(() => ClearLocalCondition());
            SaveCommand = new RelayCommand(Save);
            ExportCommand = new RelayCommand(Export);
            ShowAuditCapitalTypeInputModeCommand = new RelayCommand<AuditPayBill>(ShowAuditCapitalTypeInputMode);
            HideAuditCapitalTypeInputModeCommand = new RelayCommand<AuditPayBill>(HideAuditCapitalTypeInputMode);
            this.purchaseOrderService = purchaseOrderService;
            this.financialTerminalService = financialTerminalService;

            DepartmentList = new ObservableCollection<Department>();
            ShopList = new ObservableCollection<Shop>();
            AuditFileList = new ObservableCollection<AuditFile>();
            AuditPayBillList = new List<AuditPayBill>();
            ShowAuditPayBillList = new ObservableCollection<AuditPayBill>();
            LoadDepartment();
            StartDate = DateTime.Now.Date;
            EndDate = DateTime.Now.Date;
        }

        private void OnDeparmentSelectionChanged()
        {
            ShopList.Clear();
            foreach (var d in DepartmentList)
            {
                if (!d.IsSelected)
                    continue;
                foreach (var s in d.ShopList)
                {
                    s.IsSelected = false;
                    ShopList.Add(s);
                }
            }
        }

        private void LoadDepartment()
        {
            var dlist = JsonConvert.DeserializeObject<IList<Department>>(JsonConvert.SerializeObject(globalContext.User.DepartmentList));
            foreach (var d in dlist)
            {
                d.IsSelected = false;
                DepartmentList.Add(d);
                d.OnIsSelectedChanged = OnDeparmentSelectionChanged;
            }
            ShopList.Clear();
        }


        private void SearchHistory()
        {
            if (IsLoading)
                return;
            ClearAudit();
            IsLoading = true;
            var importShopIds = string.Join(',', ShopList.Where(s => s.IsSelected).Select(s => s.ShopId).OrderBy(s => s).ToList());
            Task.Factory.StartNew(() => financialTerminalService.GetAuditPayBillList(importShopIds, StartDate, EndDate)).ContinueWith(t =>
            {
                IsLoading = false;
                var response = t.Result;
                if (!response.Success)
                {
                    MessageBox.Show(response.Msg, "查询账单");
                    return;
                }

                var list = response.Data.Map<IList<AuditPayBill>>();
                App.Current.Dispatcher.Invoke(() =>
                {
                    foreach (var b in list)
                    {
                        b.Init(ShopList);
                        AuditPayBillList.Add(b);
                    }
                    SearchLocal();
                });
            });

        }

        private void Audit()
        {
            if (IsLoading)
                return;
            if (AuditPayBillList.Count() == 0 || !ShopList.Any(s => s.IsSelected))
            {
                MessageBox.Show("审核数据不全", "提示");
                return;
            }

            var waitList = new List<EventWaitHandle>()
            {
                new ManualResetEvent(false)
            };
            IsLoading = true;
            var shopList = ShopList.Where(s => s.IsSelected).ToList();
            var sDate = StartDate.AddDays(-5);
            var eDate = EndDate;
            Task.Factory.StartNew(() =>
            {
                AuditByPayBill(waitList[0], shopList, sDate, eDate);
                //AuditByPurchaseOrder(waitList[1]);
            }).ContinueWith(t =>
            {
                WaitHandle.WaitAll(waitList.ToArray(), -1);
                IsLoading = false;
                IsAudited = true;

                App.Current.Dispatcher.BeginInvoke((Action)delegate
                {
                    SelectAuditFile = AuditFileList.FirstOrDefault(f => f.AuditFileType == AuditFileType.账单);
                });
            });

        }

        private void AuditByPayBill(EventWaitHandle ewh, IList<Shop> shopList, DateTime startDate, DateTime endDate)
        {
            try
            {
                var auditPurchaseOrderResponse = purchaseOrderService.GetAuditPurchaseOrderList(shopList.Select(s => s.ShopId).ToList(), startDate, endDate);
                if (!auditPurchaseOrderResponse.Success)
                    throw new Exception($"获取采购单失败,{auditPurchaseOrderResponse.Msg}");

                //按日分组的pdd账单集合, key=日期 value=当日账单总额
                var pddPayBillDayDictionary = new Dictionary<DateTime, decimal>();

                foreach (var payBill in AuditPayBillList)
                {
                    payBill.IsChanged = true;

                    payBill.ErrorMessage = string.Empty;

                    #region 按日累计拼多多账单金额
                    if (payBill.MerchantOrderNo.StartsWith("XP"))
                    {
                        if (!pddPayBillDayDictionary.TryGetValue(payBill.PayTime.Value.Date, out decimal pddTotalPurchaseAmount))
                            pddPayBillDayDictionary.Add(payBill.PayTime.Value.Date, 0);
                        pddTotalPurchaseAmount += Math.Abs(payBill.ExpenditureAmount);
                        pddPayBillDayDictionary[payBill.PayTime.Value.Date] = pddTotalPurchaseAmount;
                    }
                    #endregion

                    #region 匹配采购单
                    if (string.IsNullOrEmpty(payBill.SourceMerchantOrderNo))
                    {
                        payBill.ErrorMessage = "未选资金类型";
                        continue;
                    }

                    var relationPurchaseOrder = auditPurchaseOrderResponse.Data.FirstOrDefault(p => p.PurchaseOrderId == payBill.MerchantOrderNo ||
                                                                                                    p.MerchantOrderId == payBill.MerchantOrderNo);

                    if (relationPurchaseOrder == null)
                    {
                        //if (payBill.IncomeAmount > 0 && StartDate.Day == 1)
                        //{
                        //    payBill.AuditCapitalType = AuditCapitalType.上月商品退款;
                        //    continue;
                        //}

                        if (payBill.IsSupportMerchantOrderNo)
                        {
                            //if (payBill.MerchantOrderNo.StartsWith("XP"))
                            //    payBill.AuditCapitalType = AuditCapitalType.商品采购;
                            //else
                            payBill.ErrorMessage = "未匹配采购单";
                        }
                        else
                            payBill.ErrorMessage = "未选资金类型";
                        continue;
                    }

                    payBill.RelationPurchaseOrderId = relationPurchaseOrder.PurchaseOrderId;
                    payBill.RelationShopOrderId = relationPurchaseOrder.OrderId;

                    var belongShop = shopList.FirstOrDefault(s => s.ShopId == relationPurchaseOrder.ShopId);
                    if (belongShop != null)
                    {
                        //payBill.BelongShopId = relationPurchaseOrder.ShopId;
                        //payBill.BelongShop = belongShop?.ShopName;
                        payBill.BelongShopModel = belongShop;
                    }
                    payBill.PurchasePlatform = relationPurchaseOrder.PurchasePlatform;
                    payBill.OrderStartTime = relationPurchaseOrder.OrderStartTime;


                    if (payBill.IncomeAmount > 0)
                    {
                        if (payBill.PayTime.Value.Month == relationPurchaseOrder.OrderStartTime.Value.Month)
                            payBill.AuditCapitalType = AuditCapitalType.当月商品退款;
                        else
                            payBill.AuditCapitalType = AuditCapitalType.上月商品退款;
                    }
                    else
                    {
                        if (payBill.PayTime.Value.Month == relationPurchaseOrder.OrderStartTime.Value.Month)
                            payBill.AuditCapitalType = AuditCapitalType.当月商品采购;
                        else
                            payBill.AuditCapitalType = AuditCapitalType.上月商品采购;
                    }
                    #endregion
                }

                #region 按日比较拼多多账单金额和采购单金额
                foreach (var key in pddPayBillDayDictionary)
                {
                    var purchaseAmount = auditPurchaseOrderResponse.Data.Where(p => p.PurchaseTime.Value.Date == key.Key &&
                                                                                    p.PurchasePlatform == Platform.拼多多).Sum(p => p.PurchaseAmount);
                    if (key.Value != purchaseAmount)
                    {
                        var currentDayPddPayBillList = AuditPayBillList.Where(p => p.PayTime.Value.Date == key.Key.Date &&
                                                                                   p.MerchantOrderNo.StartsWith("XP") &&
                                                                                   string.IsNullOrEmpty(p.RelationPurchaseOrderId));
                        foreach (var payBill in currentDayPddPayBillList)
                            payBill.ErrorMessage = $"{key.Key:yyyy-MM-dd}账单金额与采购单不匹配";
                    }
                }
                #endregion
            }
            catch (Exception ex)
            {
                App.Current.Dispatcher.Invoke(() => MessageBox.Show(ex.Message, "账单匹配"));
            }
            finally
            {
                ewh.Set();
            }
        }

        private void ClearAudit()
        {
            SelectAuditFile = null;
            AuditFileList.Clear();
            AuditPayBillList.Clear();
            //AuditPurchaseOrderList.Clear();
            //AuditShopOrderList.Clear();
            ShowAuditPayBillList.Clear();
            //ShowAuditPurchaseOrderList.Clear();
            //ShowAuditShopOrderList.Clear();
            IsAudited = false;
            IsShowPayBillPanel = false;
            //IsShowPurchaseOrderPanel = false;
            //IsShowShopOrderPanel = false;
            OnlyException = false;
            SelectResultShop = null;
            NoChooseFundType = false;
            NoMatchPurchaseOrder = false;
            SearchResultPurchaseOrder = string.Empty;
            SelectPurchasePlatform = null;
        }

        private (string ErrorMessage, string FileName, List<string> Lines) ImportAuditFile(AuditFileType auditFileType)
        {
            var ofd = new OpenFileDialog() { Filter = "CSV Files (*.csv)|*.csv" };
            if (ofd.ShowDialog() != true)
                return (string.Empty, string.Empty, null);
            var fileName = ofd.FileName.Substring(ofd.FileName.LastIndexOf("\\") + 1);
            var filePath = ofd.FileName;
            if (AuditFileList.Any(f => f.FileName == fileName))
                return ("文件已存在", string.Empty, null);
            try
            {
                var lines = File.ReadAllLines(filePath, Encoding.GetEncoding("GB2312")).ToList();
                AuditFileList.Add(new AuditFile() { FileName = fileName, AuditFileType = auditFileType });
                return (string.Empty, fileName, lines);
            }
            catch (Exception ex)
            {
                return (ex.Message, string.Empty, null);
            }
        }

        /// <summary>
        /// 导入支付宝账单
        /// </summary>
        private void ImportAliPayBill()
        {
            //AuditPayBillList.Clear();
            var importResult = ImportAuditFile(AuditFileType.账单);
            if (!string.IsNullOrEmpty(importResult.ErrorMessage))
            {
                MessageBox.Show(importResult.ErrorMessage, "导入支付宝账单");
                return;
            }
            if (importResult.Lines == null || importResult.Lines.Count == 0)
                return;
            //忽略前5行
            /*
            #支付宝账务明细查询											
            #账号:[20883422054731100156]											
            #起始日期:[2022年04月01日 00:00:00]   终止日期:[2022年05月01日 00:00:00]											
            #-----------------------------------------账务明细列表----------------------------------------											
            账务流水号	业务流水号	商户订单号	商品名称	发生时间	对方账号	收入金额(+元)	支出金额(-元)	账户余额(元)	交易渠道	业务类型	备注
            */
            for (var i = 0; i < 5; i++)
                importResult.Lines.RemoveAt(0);

            //忽略后4行
            /*
             #-----------------------------------------账务明细列表结束------------------------------------										
             #支出合计:681笔,共-39623.27元										
             #收入合计:85笔,共43889.26元										
             #导出时间:[2022年05月01日 10:13:45]			
             */
            for (var i = 0; i < 4; i++)
            {
                importResult.Lines.RemoveAt(importResult.Lines.Count() - 1);
            }

            var payBillNo = "";
            var list = new List<AuditPayBill>();
            try
            {
                foreach (var line in importResult.Lines)
                {
                    var array = line.CSVstrToArry();
                    var sourceMerchantOrderNo = array[2].FormatString();
                    var incomeAmount = decimal.Parse(array[6].FormatString());
                    var expenditureAmount = decimal.Parse(array[7].FormatString());
                    payBillNo = array[0].FormatString();
                    if (list.Any(p => p.PayBillNo == payBillNo))
                        continue;
                    var payBill = new AuditPayBill()
                    {
                        BelongFileName = importResult.FileName,
                        PayBillNo = payBillNo,
                        PayBillType = PayBillType.支付宝,
                        SourceMerchantOrderNo = sourceMerchantOrderNo,
                        ProductName = array[3].FormatString(),
                        PayTime = DateTime.Parse(array[4].FormatString()),
                        OppositeAccount = array[5].FormatString(),
                        ExpenditureAmount = expenditureAmount,
                        IncomeAmount = incomeAmount,
                        Remark = array[11]
                    };
                    payBill.MerchantOrderNo = payBill.SourceMerchantOrderNo;
                    if (payBill.MerchantOrderNo == null)
                        payBill.MerchantOrderNo = "";
                    if (payBill.SourceMerchantOrderNo.StartsWith("T50060NP"))
                    {
                        payBill.MerchantOrderNo = payBill.SourceMerchantOrderNo.Substring(8);
                        payBill.IsSupportMerchantOrderNo = true;
                    }

                    if (payBill.SourceMerchantOrderNo.StartsWith("T200P"))
                    {
                        payBill.MerchantOrderNo = payBill.SourceMerchantOrderNo.Substring(5);
                        payBill.IsSupportMerchantOrderNo = true;
                    }

                    if (payBill.SourceMerchantOrderNo.StartsWith("XP"))
                    {
                        payBill.IsSupportMerchantOrderNo = true;
                    }

                    list.Add(payBill);
                }
                //list = list.OrderByDescending(p => p.PayTime).ToList();
                foreach (var p in list)
                    AuditPayBillList.Add(p);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"问题账单号{payBillNo} {ex.Message}", "导入支付宝账单");
            }
        }

        private void ClearLocalCondition(bool isSearch = true)
        {
            OnlyException = false;
            NoMatchPurchaseOrder = false;
            NoChooseFundType = false;
            SelectResultShop = null;
            SelectPurchasePlatform = null;
            SearchResultPurchaseOrder = string.Empty;
            if (isSearch)
                SearchLocal();
        }

        /// <summary>
        /// 采购审计文件对象改变事件
        /// </summary>
        private void SearchLocal()
        {
            //if (SelectAuditFile == null)
            //    return;
            //if (SelectAuditFile.AuditFileType == AuditFileType.账单)
            //{
            IsShowPayBillPanel = true;
            ShowAuditPayBillList.Clear();
            var where = AuditPayBillList.Where(b => true);
            if (SelectAuditFile != null)
                where = where.Where(b => b.BelongFileName == SelectAuditFile.FileName);
            if (OnlyException)
                where = where.Where(b => !string.IsNullOrEmpty(b.ErrorMessage));
            if (NoMatchPurchaseOrder)
                where = where.Where(b => !string.IsNullOrEmpty(b.ErrorMessage) && b.ErrorMessage == "未匹配采购单");
            if (NoChooseFundType)
                where = where.Where(b => !string.IsNullOrEmpty(b.ErrorMessage) && b.ErrorMessage == "未选资金类型");
            if (SelectResultShop != null)
                where = where.Where(b => b.BelongShopId != null && b.BelongShopId.Value == SelectResultShop.ShopId);
            if (!string.IsNullOrEmpty(SearchResultPurchaseOrder))
                where = where.Where(b => !string.IsNullOrEmpty(b.RelationPurchaseOrderId) && b.RelationPurchaseOrderId.Contains(SearchResultPurchaseOrder));
            if (SelectPurchasePlatform != null)
                where = where.Where(b => b.PurchasePlatform == SelectPurchasePlatform);
            var list = where.ToList();
            foreach (var b in list)
                ShowAuditPayBillList.Add(b);
            //}
        }

        private void Save()
        {
            if (ShowAuditPayBillList.Count == 0)
            {
                MessageBox.Show("没有需要保存的数据", "提示");
                return;
            }

            var saveList = ShowAuditPayBillList.Where(p => p.IsChanged).ToList();
            if (saveList.Count == 0)
            {
                MessageBox.Show("没有需要保存的账单");
                return;
            }

            var importShopIds = string.Join(',', ShopList.Where(s => s.IsSelected).Select(s => s.ShopId).OrderBy(s => s).ToList());

            var replaceResponse = financialTerminalService.IsExistAuditPayBill(importShopIds, StartDate, EndDate);
            if (!replaceResponse.Success)
            {
                MessageBox.Show("检查重复账单失败", "提示");
                return;
            }

            if (replaceResponse.Data)
                if (MessageBox.Show("存在重复账单数据,是否覆盖", "确认", MessageBoxButton.OKCancel) != MessageBoxResult.OK)
                    return;

            IsLoading = true;

            foreach (var bill in ShowAuditPayBillList)
                bill.ImportShopIds = importShopIds;

            Task.Factory.StartNew(() => financialTerminalService.BatchInsertAuditPayBill(saveList)).ContinueWith(t =>
            {
                IsLoading = false;
                var insertResponse = t.Result;
                App.Current.Dispatcher.Invoke(() =>
                {
                    if (insertResponse.Success)
                    {
                        foreach (var p in saveList)
                            p.IsChanged = false;
                        MessageBox.Show("保存成功", "提示");
                    }
                    else
                        MessageBox.Show(insertResponse.Msg, "提示");
                });
            });

        }

        private void Export()
        {
            if (ShowAuditPayBillList.Count == 0)
                return;
            var shopNames = string.Join(',', ShopList.Where(s => s.IsSelected).Select(s => s.ShopName));

            var ew = new ProcurementAuditExcelExport();
            if (ew.ShowDialog() != true)
                return;

            var fileName = string.Empty;
            var saveList = new List<string>();
            if (ew.Type == 0)
            {
                fileName = $"{StartDate:yyyy-MM-dd}_{EndDate:yyyy-MM-dd}_{shopNames}_审计结果.csv";
                saveList.AddRange(ShowAuditPayBillList.Select(p => p.ToString()).ToList());
                saveList.Insert(0, AuditPayBill.ExportTitle);
            }
            else
            {
                fileName = $"{StartDate:yyyy-MM-dd}_{EndDate:yyyy-MM-dd}_{shopNames}_资金类型汇总.csv";
                saveList.Add($"序号,资金类型,{string.Join(',', ShopList)},汇总");
                var capitalGroups = ShowAuditPayBillList.Where(p => p.AuditCapitalType != null).GroupBy(p => p.AuditCapitalType);
                var index = 1;
                var rowBuilder = new StringBuilder();
                foreach (var capitalGroup in capitalGroups)
                {
                    var sum = 0M;
                    rowBuilder.Append($"{index},{capitalGroup.Key},");
                    foreach (var shop in ShopList)
                    {
                        var currentShopCapitalGroup = capitalGroup.Where(p => p.BelongShopId == shop.ShopId);
                        var amount = 0M;
                        if (currentShopCapitalGroup.Count() > 0)
                        {
                            if (capitalGroup.Key == AuditCapitalType.当月商品退款 || capitalGroup.Key == AuditCapitalType.上月商品退款)
                                amount = currentShopCapitalGroup.Sum(p => p.IncomeAmount);
                            else
                                amount = currentShopCapitalGroup.Sum(p => p.ExpenditureAmount);
                        }
                        sum += amount;
                        rowBuilder.Append($"{amount},");
                    }
                    rowBuilder.Append($"{sum}");
                    index++;
                    saveList.Add(rowBuilder.ToString());
                    rowBuilder.Clear();
                }
            }

            var sfd = new SaveFileDialog() { FileName = fileName };
            if (sfd.ShowDialog() != true)
                return;
            var path = sfd.FileName;

            try
            {
                File.WriteAllLines(path, saveList, Encoding.UTF8);
                MessageBox.Show("导出成功", "提示");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "导出审计结果");
            }
        }

        private void ShowAuditCapitalTypeInputMode(AuditPayBill auditPayBill)
        {
            auditPayBill.AuditCapitalTypeInputMode = 1;
        }

        private void HideAuditCapitalTypeInputMode(AuditPayBill auditPayBill)
        {
            auditPayBill.AuditCapitalTypeInputMode = 0;
        }


    }
}