using ButcherFactory.BO;
using ButcherFactory.BO.LocalBL;
using ButcherFactory.BO.Utils;
using ButcherFactory.Controls;
using ButcherFactory.Dialogs;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using WinFormControl;

namespace ButcherFactory.SegmentStockUp_
{
  public partial class SegmentStockUpForm : FormTemplate, IWithRoleForm
  {
    #region IWithRoleForm
    public List<short> RoleName
    {
      get { return new List<short> { (short)设备类别.销售备货 }; }
    }

    public Form Generate()
    {
      return this;
    }
    #endregion

    Tuple<string, long> selectedCustomer;

    DateTime sendTime = DateTime.Today;
    SegmentStockUpConfig config;

    BindingList<SaleOutStoreInfo> mainList;
    BindingList<SegmentStockUp> detailList;
    BindingList<DeliverGoodsLineTemp> finishList;

    List<SaleOutStoreInfo> allMain;
    List<SegmentStockUp> allDetail;
    List<AlreadyStockUp> alreadyList;

    Thread syncStockdNumber;
    Thread refreshFromServer;
    Thread loadBindTask;//onetime
    List<long> mLineGroupIds = new List<long>();

    public SegmentStockUpForm()
    {
      config = XmlUtil.DeserializeFromFile<SegmentStockUpConfig>();
      InitializeComponent();
      finishList = new BindingList<DeliverGoodsLineTemp>();
      allMain = new List<SaleOutStoreInfo>();
      allDetail = new List<SegmentStockUp>();
      alreadyList = new List<AlreadyStockUp>();
      // dataPicker.Text = sendTime.ToString("yyyy-MM-dd");
      uScanPanel1.AfterScan += uScanPanel1_AfterScan;
      this.FormClosing += delegate
      {
        AbortTask();
      };
    }

    void AbortTask()
    {
      if (loadBindTask != null && loadBindTask.IsAlive)
        loadBindTask.Abort();
      if (syncStockdNumber != null && syncStockdNumber.IsAlive)
        syncStockdNumber.Abort();
      if (refreshFromServer != null && refreshFromServer.IsAlive)
        refreshFromServer.Abort();
    }

    protected override void OnLoad(EventArgs e)
    {
      BindDeliverLineGroup(false);
      downWeightBox.Text = string.Format("{0:#0.######}", config.AllowDownWeight);
      StartTask();
      base.OnLoad(e);
    }

    void StartTask()
    {
      allDetail = SegmentStockUpBL.GetLocalList(sendTime);
      loadBindTask = new Thread(LoadBind);
      loadBindTask.Start();
      syncStockdNumber = new Thread(SyncStockdNumber);
      syncStockdNumber.Start();
      refreshFromServer = new Thread(RefreshFromServer);
      refreshFromServer.Start();
    }

    private void LoadBind()
    {
      var mainList = SegmentStockUpBL.GetSaleOutStoreList(sendTime);
      var appendAlready = SegmentStockUpBL.SyncAlreadyNumber(mainList.Select(x => x.DetailID), null);
      ReBind(mainList, appendAlready);
    }

    object _lock = new object();
    //loadBind,Refresh,  taskMain,taskAlready,Scan
    void ReBind(List<SaleOutStoreInfo> mainList, List<AlreadyStockUp> appendAlready)
    {
      lock (_lock)
      {
        AppendData(mainList, appendAlready);
        var needRefresh = PrepareFinishList();

        if (needRefresh)
          BindFinishGrid();
      }
    }

    void AppendData(List<SaleOutStoreInfo> mainList, List<AlreadyStockUp> appendAlready)
    {
      if (mainList.Any())
        allMain = mainList;
      foreach (var item in appendAlready)
      {
        var first = alreadyList.FirstOrDefault(x => x.DetailID == item.DetailID);
        if (first == null)
        {
          first = item;
          alreadyList.Add(item);
        }
        else if (first.MaxID < item.MaxID)
        {
          first.MaxID = item.MaxID;
          first.UnitNum = (first.UnitNum ?? 0) + (item.UnitNum ?? 0);
          first.SecondNumber = (first.SecondNumber ?? 0) + (item.SecondNumber ?? 0);
        }
        else
          continue;

        //局部更新
        if (!mainList.Any())
          UpdateMainInfo(first);
      }

      //全量更新
      if (mainList.Any())
      {
        foreach (var item in alreadyList)
          UpdateMainInfo(item);
      }
    }

    void UpdateMainInfo(AlreadyStockUp item)
    {
      var mainFirst = allMain.FirstOrDefault(x => x.DetailID == item.DetailID);
      if (mainFirst != null)
      {
        mainFirst.StandardPic = false;// item.StandardPic;
        mainFirst.SUnitNum = item.UnitNum;
        mainFirst.SSecondNumber = item.SecondNumber;
        mainFirst.DownFloat = config.AllowDownWeight;
      }
    }

    //返回是否需要更新Grid;
    bool PrepareFinishList()
    {
      var old = finishList.ToList();
      var append = new List<DeliverGoodsLineTemp>();
      finishList = new BindingList<DeliverGoodsLineTemp>();
      var idx = 0;
      foreach (var item in allMain.GroupBy(x => x.Customer_Name).Where(x => x.All(y => y.Finishd)))
      {
        var detail = new DeliverGoodsLineTemp();
        detail.RowIndex = ++idx;
        detail.Name = item.Key;
        detail.UnitNum = item.Sum(x => x.UnitNum ?? 0);
        detail.SecondNumber = item.Sum(x => x.SecondNumber ?? 0);
        detail.SUnitNum = item.Sum(x => x.SUnitNum ?? 0);
        detail.SSecondNumber = item.Sum(x => x.SSecondNumber ?? 0);
        if (!old.Any(x => x.Name == item.Key))
        {
          idx--;
          append.Add(detail);
        }
        else
          finishList.Insert(0, detail);
      }

      foreach (var item in append)
      {
        item.RowIndex = ++idx;
        finishList.Insert(0, item);
      }

      if (old.Count != finishList.Count)
        return true;
      return old.Except(finishList).Count() != 0;
    }

    void BindFinishGrid()
    {
      this.Invoke(new Action(() =>
      {
        finishGrid.DataSource = finishList;
        if (finishList.Any())
          finishGrid.Rows[0].Selected = true;
        finishGrid.Refresh();
      }));
    }

    private void SyncStockdNumber()
    {
      while (true)
      {
        Thread.Sleep(2000);
        IEnumerable<long> tags = new List<long>();
        long? maxID = null;
        if (alreadyList.Any())
          maxID = alreadyList.Max(x => x.MaxID);
        else
          tags = allMain.Select(x => x.DetailID);

        if (maxID.HasValue || tags.Any())
        {
          var temp = SegmentStockUpBL.SyncAlreadyNumber(tags, maxID);
          if (temp.Any())
          {
            ReBind(new List<SaleOutStoreInfo>(), temp);
          }
        }
      }
    }

    private void RefreshFromServer()
    {
      while (true)
      {
        Thread.Sleep(2 * 60 * 1000);
        var temp = SegmentStockUpBL.GetSaleOutStoreList(sendTime);
        if (temp.Any())
        {
          ReBind(temp, new List<AlreadyStockUp>());
        }
      }
    }

    void uScanPanel1_AfterScan()
    {
      var code = uScanPanel1.TextBox.Text;
      if (string.IsNullOrEmpty(code))
        return;
      if (allDetail.Any(x => x.BarCode == code))
      {
        InfoBox.Show("错误", "条码已使用过", Color.Green, 1, this);
        return;
      }
      var info = SegmentStockUpBL.StockUpScan(code);
      if (info == null)
      {
        InfoBox.Show("错误", "条码未入库", Color.Blue, 1, this);
        return;
      }

      InsertDetail(info);
    }

    void InsertDetail(Tuple<string, decimal?, bool> scan)
    {
      SaleOutStoreInfo saleOutStore;
      if (selectedCustomer != null)
        saleOutStore = allMain.FirstOrDefault(x => x.Customer_Name == selectedCustomer.Item1 && !x.Finishd && x.Goods_Code == scan.Item1);
      else
        saleOutStore = allMain.FirstOrDefault(x => mLineGroupIds.Contains(x.DeliverLineGroup_ID ?? 0) && !x.Finishd && x.Goods_Code == scan.Item1);
      if (saleOutStore == null)
      {
        InfoBox.Show("提示", "没有订单", Color.Red, 1, this);
        return;
      }
      var detail = new SegmentStockUp();
      detail.BarCode = uScanPanel1.TextBox.Text;
      detail.Date = sendTime;
      detail.DetailID = saleOutStore.DetailID;
      detail.DeliverGoodsLine_Name = saleOutStore.DeliverGoodsLine_Name;
      detail.Goods_Name = saleOutStore.Goods_Name;
      //detail.BillID = saleOutStore.BillID;
      detail.Customer_Name = saleOutStore.Customer_Name;
      detail.UnitNumber = scan.Item2;
      detail.StandardPic = scan.Item3;
      //if (detail.UnitNumber.HasValue && saleOutStore.Rate.HasValue)
      //  detail.SecondNumber = detail.UnitNumber * saleOutStore.Rate;
      //else
      detail.SecondNumber = 1;
      var number = 0m;
      if (saleOutStore.StockUpBySecondNum)
        number = saleOutStore.SecondNumber ?? 0;
      else
        number = (saleOutStore.UnitNum ?? 0) - (config.AllowDownWeight ?? 0);
      //if (!detail.StandardPic)
      //  number = saleOutStore.SecondNumber;

      var already = alreadyList.FirstOrDefault(x => x.DetailID == detail.DetailID);
      if (already == null)
        already = new AlreadyStockUp() { DetailID = detail.DetailID };//StandardPic = detail.StandardPic
      var back = SegmentStockUpBL.Insert(detail, already, number, saleOutStore.StockUpBySecondNum);
      if (back == null)
      {
        InfoBox.Show("提示", "网络错误！", Color.Red, 1, this);
        return;
      }
      if (back.State == -1)
      {
        InfoBox.Show("提示", "条码已使用过", Color.Green, 1, this);
        return;
      }
      //back.StandardPic = detail.StandardPic;
      back.DetailID = detail.DetailID;
      if (back.State == 0)
      {
        ReBind(new List<SaleOutStoreInfo>(), new List<AlreadyStockUp> { back });
        InsertDetail(scan);
        return;
      }
      if (back.State != 1)
      {
        InfoBox.Show("提示", "未知状态" + back.State, Color.Green, 1, this);
        return;
      }
      ReBind(new List<SaleOutStoreInfo>(), new List<AlreadyStockUp> { back });
      allDetail.Add(detail);

      if (printCk.Checked)
      {
        var last = 0m;
        //  allMain.Where(x => x.Goods_Name == saleOutStore.Goods_Name && x.DeliverGoodsLine_Name == saleOutStore.DeliverGoodsLine_Name)
        //  .Sum(x => ((x.UnitNum ?? 0) - (x.SUnitNum ?? 0)) < 0 ? 0 : ((x.UnitNum ?? 0) - (x.SUnitNum ?? 0)));
        //if (last < 0)
        //  last = 0;
        SegmentStockUpPrint.Print(detail, last, saleOutStore);
      }
      var hasUnFinish = allMain.Where(x => x.Customer_Name == saleOutStore.Customer_Name).Any(x => !x.Finishd);
      if (!hasUnFinish)
        InfoBox.Show("提示", string.Format("{0} 备货完成", saleOutStore.Customer_Name), Color.Green, 1, this);
      BindMainGrid(saleOutStore);
    }

    void BindMainGrid(SaleOutStoreInfo saleOutStore)
    {
      var main = new List<SaleOutStoreInfo>();
      foreach (var g in allMain.Where(x => x.Goods_Name == saleOutStore.Goods_Name).GroupBy(x => x.Customer_Name))
      {
        var item = new SaleOutStoreInfo();
        var f = g.First();
        main.Add(item);
        item.Customer_Name = g.Key;
        item.Goods_Name = f.Goods_Name;
        item.Goods_Spec = f.Goods_Spec;
        item.SecondNumber = g.Sum(x => x.SecondNumber ?? 0);
        item.UnitNum = g.Sum(x => x.UnitNum ?? 0);
        item.SSecondNumber = g.Sum(x => x.SSecondNumber ?? 0);
        item.SUnitNum = g.Sum(x => x.SUnitNum ?? 0);
        item.DownFloat = config.AllowDownWeight;
        item.StockUpBySecondNum = f.StockUpBySecondNum;
        item.FinishAssign = f.FinishAssign;
      }
      mainList = new BindingList<SaleOutStoreInfo>(main.OrderBy(x => x.Finishd).ToList());

      mainGridView.DataSource = mainList;
      mainGridView.Refresh();
      BindDetail(main.Where(x => x.Customer_Name == saleOutStore.Customer_Name).First());
    }

    void BindDetail(SaleOutStoreInfo first)
    {
      //if (first != null)
      //{
      driveLineLbl.Text = first.DeliverGoodsLine_Name;
      goodsLbl.Text = first.Goods_Name;

      dhNumberLbl.Text = string.Format("{0:#0.##}", first.SecondNumber);
      dhUnitNumLbl.Text = string.Format("{0:#0.##}", first.UnitNum);
      bhNumberLbl.Text = string.Format("{0:#0.##}", first.SSecondNumber);
      bhUnitNumLbl.Text = string.Format("{0:#0.##}", first.SUnitNum);
      var detail = allDetail.Where(x => x.Customer_Name == first.Customer_Name && x.Goods_Name == first.Goods_Name).OrderByDescending(x => x.ID);
      detailList = new BindingList<SegmentStockUp>(detail.ToList());
      //}
      //else
      //{
      //  driveLineLbl.Text = string.Empty;
      //  goodsLbl.Text = string.Empty;
      //  dhNumberLbl.Text = string.Empty;
      //  dhUnitNumLbl.Text = string.Empty;
      //  bhNumberLbl.Text = string.Empty;
      //  bhUnitNumLbl.Text = string.Empty;

      //  detailList = new BindingList<SegmentStockUp>();
      //}
      detailGridView.DataSource = detailList;
      detailGridView.Refresh();
    }

    private void refresh_Click(object sender, EventArgs e)
    {
      AbortTask();
      StartTask();
    }

    private void mainGridView_CellClick(object sender, DataGridViewCellEventArgs e)
    {
      if (e.RowIndex < 0)
        return;
      var item = mainGridView.CurrentRow.DataBoundItem as SaleOutStoreInfo;
      BindDetail(item);
    }

    private void mainGridView_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
    {
      DataGridViewRow dgrSingle = mainGridView.Rows[e.RowIndex];
      var v = (bool)dgrSingle.Cells["D_Finishd"].Value;
      if (v)
      {
        dgrSingle.DefaultCellStyle.BackColor = Color.YellowGreen;
      }
    }

    private void colorButton1_Click(object sender, EventArgs e)
    {
      var detail = new SegmentStockUp() { DeliverGoodsLine_Name = "青岛龙钰聚祥万福批发部", Date = DateTime.Today, BarCode = "260912011201905120100005" };
      var last = 5.234m;
      var saleOutStore = new SaleOutStoreInfo() { Customer_Name = "青岛市大客户", SendQueue = 51 };
      SegmentStockUpPrint.Print(detail, last, saleOutStore);
    }

    private void label2_Click(object sender, EventArgs e)
    {
      var dialog = new SelectCustomerDialog();
      if (dialog.ShowDialog() == DialogResult.OK)
      {
        selectedCustomer = dialog.Result;
        if (selectedCustomer == null)
          label2.Text = "请选择";
        else
          label2.Text = selectedCustomer.Item1;
      }
    }

    private void downWeightBox_Click(object sender, EventArgs e)
    {
      var pad = new NumberPad();
      if (pad.ShowDialog() == true)
      {
        decimal? weight = null;
        if (!string.IsNullOrEmpty(pad.Result))
        {
          decimal v;
          if (decimal.TryParse(pad.Result, out v))
            weight = v;
          else
            throw new Exception("输入错误");
        }
        downWeightBox.Text = string.Format("{0:#0.######}", weight);
        config.AllowDownWeight = weight;
        XmlUtil.SerializerObjToFile(config);
      }
    }

    private void lineGroupSetBtn_Click(object sender, EventArgs e)
    {
      new DeliverLineGroupSelectDialog().ShowDialog();
      BindDeliverLineGroup(true);
    }

    Color color = Color.FromArgb(105, 105, 105);
    Color selectColor = Color.FromArgb(250, 120, 24);
    void BindDeliverLineGroup(bool loadNew)
    {
      flowLayoutPanel1.Controls.Clear();
      mLineGroupIds.Clear();
      if (loadNew)
        config = XmlUtil.DeserializeFromFile<SegmentStockUpConfig>();
      foreach (var item in config.LineGroup)
      {
        var btn = new ColorButton() { Width = 150, Height = 60, Text = item.Name, Tag = item, Font = new Font("宋体", 14), Margin = new Padding(30) };
        btn.BackColor = color;
        btn.Click += DeliverLineBtn_Click;
        flowLayoutPanel1.Controls.Add(btn);
      }
    }

    private void DeliverLineBtn_Click(object sender, EventArgs e)
    {
      var btn = sender as ColorButton;
      var item = (DeliverLineGroup)btn.Tag;
      var first = mLineGroupIds.FirstOrDefault(x => x == item.ID);
      if (first == 0)
      {
        mLineGroupIds.Add(item.ID);
        btn.BackColor = selectColor;
      }
      else
      {
        mLineGroupIds.Remove(item.ID);
        btn.BackColor = color;
      }
    }
  }

  class DeliverGoodsLineTemp
  {
    public string Name { get; set; }

    public int RowIndex { get; set; }

    public decimal? SecondNumber { get; set; }
    public decimal? UnitNum { get; set; }
    public decimal? SSecondNumber { get; set; }
    public decimal? SUnitNum { get; set; }

    public override bool Equals(object obj)
    {
      var tag = obj as DeliverGoodsLineTemp;
      return tag.Name == this.Name
        && tag.UnitNum == this.UnitNum
        && tag.SecondNumber == this.SecondNumber
        && tag.SUnitNum == this.SUnitNum
        && tag.SSecondNumber == this.SSecondNumber;
    }

    public override int GetHashCode()
    {
      var hc1 = Name.GetHashCode();
      var hc2 = UnitNum.GetHashCode();
      var hc3 = SecondNumber.GetHashCode();
      var hc4 = SUnitNum.GetHashCode();
      var hc5 = SSecondNumber.GetHashCode();
      return hc1 ^ hc2 ^ hc3 ^ hc4 ^ hc5;
    }
  }
}
