<?php

namespace App\Support;

use App\Models\AccountTransaction;
use App\Models\Product;
use App\Models\Purchase;
use App\Models\PurchaseItem;
use App\Models\PurchasePayment;
use App\Models\Sale;
use App\Models\SaleMeta;
use App\Models\SalePayment;
use App\Models\StockMovement;
use App\Models\SupplierLedger;
use Illuminate\Support\Collection;

class InventoryConsistency
{
    public static function deleteStockMovements(string $referenceNo, array $types = []): void
    {
        $query = StockMovement::where('reference_no', $referenceNo);
        if (!empty($types)) {
            $query->whereIn('movement_type', $types);
        }
        $query->delete();
    }

    public static function rebuildSupplierLedger(int $supplierId): void
    {
        $entries = SupplierLedger::where('supplier_id', $supplierId)
            ->orderBy('entry_date')
            ->orderBy('id')
            ->get();

        $balance = 0;
        foreach ($entries as $entry) {
            $balance += (float) $entry->debit - (float) $entry->credit;
            $entry->balance = $balance;
            $entry->save();
        }
    }

    public static function deleteSupplierReferenceArtifacts(Purchase $purchase): void
    {
        PurchasePayment::where('purchase_id', $purchase->id)->delete();
        AccountTransaction::where('reference_no', $purchase->invoice_no)
            ->where('party_type', 'Supplier')
            ->where('party_id', $purchase->supplier_id)
            ->delete();
        SupplierLedger::where('supplier_id', $purchase->supplier_id)
            ->where('reference_no', $purchase->invoice_no)
            ->delete();

        if ($purchase->supplier_id) {
            self::rebuildSupplierLedger((int) $purchase->supplier_id);
        }
    }

    public static function reversePurchaseInventory(Purchase $purchase): void
    {
        $purchase->loadMissing('items');

        foreach ($purchase->items as $item) {
            if (!$item->product_id) {
                continue;
            }

            $product = Product::lockForUpdate()->find($item->product_id);
            if (!$product) {
                continue;
            }

            $current = (int) $product->stock_quantity;
            $qty = (int) ($item->qty_in_base ?? $item->qty);
            if ($current < $qty) {
                throw new \RuntimeException("Cannot reverse purchase for {$product->product_name}. Current stock is lower than purchased quantity.");
            }

            $product->decrement('stock_quantity', $qty);
        }

        self::deleteStockMovements($purchase->invoice_no, ['purchase']);
    }

    public static function deleteSaleArtifacts(string $invoiceNo): void
    {
        SalePayment::where('invoice_no', $invoiceNo)->delete();
        SaleMeta::where('invoice_no', $invoiceNo)->delete();
        self::deleteStockMovements($invoiceNo, ['sale']);
    }

    public static function reverseSaleInventory(Collection $sales): void
    {
        foreach ($sales as $sale) {
            if (!$sale->product_id) {
                continue;
            }

            $product = Product::lockForUpdate()->find($sale->product_id);
            if ($product) {
                $product->increment('stock_quantity', (int) ($sale->quantity_sold_base ?? $sale->quantity_sold));
            }
        }

        if ($sales->isNotEmpty()) {
            self::deleteStockMovements((string) $sales->first()->invoice_no, ['sale']);
        }
    }

    public static function totalPreviouslyReturnedForSale(int $saleId): float
    {
        return (float) \App\Models\SaleReturnItem::where('sale_id', $saleId)->sum('qty');
    }

    public static function totalPreviouslyReturnedForPurchaseItem(int $purchaseItemId): float
    {
        return (float) \App\Models\SupplierReturnItem::where('purchase_item_id', $purchaseItemId)->sum('qty');
    }
}
