using Indotalent.Data.Entities;
using Indotalent.Data.Enums;
using Indotalent.Infrastructure.Database;
using Microsoft.EntityFrameworkCore;

namespace Indotalent.Shared.Utils;

public static class InventoryTransactionHelper
{
    public static void CalculateInvenTrans(AppDbContext context, InventoryTransaction transaction)
    {
        if (transaction == null)
        {
            throw new Exception("Inventory transaction is null");
        }

        var moduleName = transaction.ModuleName;

        if (moduleName != "StockCount" && (transaction.Movement ?? 0.0) <= 0.0)
        {
            throw new Exception("Quantity must not zero and should be positive.");
        }

        if (moduleName == "StockCount" && (transaction.QtySCCount ?? 0.0) <= 0.0)
        {
            throw new Exception("Quantity must not zero and should be positive.");
        }

        switch (moduleName)
        {
            case "DeliveryOrder":
                transaction.TransType = InventoryTransType.Out;
                transaction.WarehouseFromId = transaction.WarehouseId;
                transaction.WarehouseToId = GetSystemWarehouseId(context, "CUSTOMER");
                break;

            case "GoodsReceive":
                transaction.TransType = InventoryTransType.In;
                transaction.WarehouseFromId = GetSystemWarehouseId(context, "VENDOR");
                transaction.WarehouseToId = transaction.WarehouseId;
                break;

            case "SalesReturn":
                transaction.TransType = InventoryTransType.In;
                transaction.WarehouseFromId = GetSystemWarehouseId(context, "VENDOR");
                transaction.WarehouseToId = transaction.WarehouseId;
                break;

            case "PurchaseReturn":
                transaction.TransType = InventoryTransType.Out;
                transaction.WarehouseFromId = transaction.WarehouseId;
                transaction.WarehouseToId = GetSystemWarehouseId(context, "CUSTOMER");
                break;

            case "TransferIn":
                transaction.TransType = InventoryTransType.In;
                transaction.WarehouseFromId = GetSystemWarehouseId(context, "TRANSIT");
                transaction.WarehouseToId = transaction.WarehouseId;
                break;

            case "TransferOut":
                transaction.TransType = InventoryTransType.Out;
                transaction.WarehouseFromId = transaction.WarehouseId;
                transaction.WarehouseToId = GetSystemWarehouseId(context, "TRANSIT");
                break;

            case "StockCount":
                transaction.QtySCSys = GetStock(context, transaction.WarehouseId, transaction.ProductId, transaction.Id);
                transaction.QtySCDelta = transaction.QtySCSys - transaction.QtySCCount;
                transaction.Movement = Math.Abs(transaction.QtySCDelta ?? 0.0);

                if (transaction.QtySCDelta < 0.0)
                {
                    transaction.TransType = InventoryTransType.In;
                    transaction.WarehouseFromId = GetSystemWarehouseId(context, "STOCK_COUNT");
                    transaction.WarehouseToId = transaction.WarehouseId;
                }
                else
                {
                    transaction.TransType = InventoryTransType.Out;
                    transaction.WarehouseFromId = transaction.WarehouseId;
                    transaction.WarehouseToId = GetSystemWarehouseId(context, "STOCK_COUNT");
                }
                break;

            case "NegativeAdjustment":
                transaction.TransType = InventoryTransType.Out;
                transaction.WarehouseFromId = transaction.WarehouseId;
                transaction.WarehouseToId = GetSystemWarehouseId(context, "ADJUSTMENT");
                break;

            case "PositiveAdjustment":
                transaction.TransType = InventoryTransType.In;
                transaction.WarehouseFromId = GetSystemWarehouseId(context, "ADJUSTMENT");
                transaction.WarehouseToId = transaction.WarehouseId;
                break;

            case "Scrapping":
                transaction.TransType = InventoryTransType.Out;
                transaction.WarehouseFromId = transaction.WarehouseId;
                transaction.WarehouseToId = GetSystemWarehouseId(context, "SCRAPPING");
                break;
        }

        transaction.Stock = (transaction.Movement ?? 0.0) * (int)(transaction.TransType ?? InventoryTransType.In);
    }

    public static double GetStock(AppDbContext context, string? warehouseId, string? productId, string? currentId = null)
    {
        return context.InventoryTransaction
            .Where(x =>
                x.Status == InventoryTransactionStatus.Confirmed &&
                x.WarehouseId == warehouseId &&
                x.ProductId == productId &&
                x.Id != currentId)
            .Sum(x => x.Stock ?? 0.0);
    }

    private static string? GetSystemWarehouseId(AppDbContext context, string name)
    {
        return context.Warehouse
            .Where(x => x.SystemWarehouse == true && x.Name == name)
            .Select(x => x.Id)
            .FirstOrDefault();
    }
}