using InABox.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Comal.Classes
{
    /// 
    /// The  is the way that we are allowing a single  to, when received,
    /// have its stock distributed to multiple sources. The current idea is this:
    /// 
    /// 
    ///     - 
    ///         The  itself has a  and a .
    ///         In most cases, this will be the target for received stock, and
    ///         in this simple case, there are no POIAs. If the  is blank, it goes to general stock;
    ///         otherwise, it goes to a specific allocation.
    ///     ///
- 
    ///         If there are allocations, this cuts into the , such that after any allocations have been filled,
    ///         the remainder of the stock goes to the .
    ///         If the allocations total more than , then a negative stock movement
    ///         is registered against .
    ///     ///
- 
    ///         In the case of Dimension conversions (see ), the quantity on the allocation is after the conversion has
    ///         happened.
 ///         This is important, because in this case, there will be a discrepancy between  and the total
    ///         of .
    ///
 ///         As an example, suppose we are purchasing 2 boxes of 1000 screws. Then, the allocations are by numbers of screws, so that 800 might go to
    ///         Job A, 600 to Job B and 600 to general stock. So the allocation quantities are the actual numbers that will be on the stock movements.
    ///
///
/// 
    [Caption("Allocation")]
    public class PurchaseOrderItemAllocation : Entity, IRemotable, IPersistent, ILicense
    , IOneToMany, IOneToMany, IOneToMany, IPostableFragment
    {
        [EntityRelationship(DeleteAction.Cascade)]
        public PurchaseOrderItemLink Item { get; set; }
        
        [EntityRelationship(DeleteAction.Cascade)]
        [EditorSequence(1)]
        public JobLink Job { get; set; }
        
        private class JobRequisitionItemLookup : LookupDefinitionGenerator
        {
            public override Columns DefineFilterColumns()
            {
                return base.DefineFilterColumns().Add(x => x.Job.ID).Add(x => x.Item.Product.ID);
            }
            public override Filter? DefineFilter(PurchaseOrderItemAllocation[] items)
            {
                var jobIDs = items.Select(x => x.Job.ID).Distinct().ToArray();
                if(jobIDs.Length > 1)
                {
                    return new Filter().None();
                }
                var jobID = jobIDs.FirstOrDefault();
                var productID = items.Select(x => x.Item.Product.ID).FirstOrDefault();
                if(productID == Guid.Empty)
                {
                    return new Filter().None();
                }
                return new Filter(x => x.Job.ID).IsEqualTo(jobID)
                    .And(x => x.Product.ID).IsEqualTo(productID);
            }
            public override Columns DefineColumns()
            {
                return Columns.None().Add(x => x.Job.JobNumber).Add(x => x.Requisition.Number).Add(x => x.Requisition.Description);
            }
            public override string FormatDisplay(CoreRow row)
            {
                var jobNumber = row.Get(x => x.Job.JobNumber);
                var requiNumber = row.Get(x => x.Requisition.Number);
                var requiDesc = row.Get(x => x.Requisition.Description);
                return $"{jobNumber}: #{requiNumber} ({requiDesc})";
            }
        }
        /// 
        /// This may be an empty link. The interface is as such: if there is no JRI, then we are creating a reserve and allocation just against the job. If there is a JRI,
        /// then received stock is reserved and allocated for the JRI.
        /// 
        [EntityRelationship(DeleteAction.Cascade)]
        [LookupDefinition(typeof(JobRequisitionItemLookup))]
        [EditorSequence(2)]
        public JobRequisitionItemLink JobRequisitionItem { get; set; }
        
        [EditorSequence(3)]
        public double Quantity { get; set; }
        [NullEditor]
        public string PostedReference { get; set; }
        protected override void DoPropertyChanged(string name, object? before, object? after)
        {
            base.DoPropertyChanged(name, before, after);
            if(name == $"{nameof(Job)}.{nameof(Job.ID)}")
            {
                JobRequisitionItem.ID = Guid.Empty;
                JobRequisitionItem.Clear();
            }
        }
    }
    
    
    public class PurchaseOrderItemAllocationJobLink : EntityLink
    {
        [NullEditor]
        public override Guid ID { get; set; }
        
        public LightJobLink Job { get; set; }
        
        public LightPurchaseOrderItemLink Item { get; set; }
        
    }
}