<?php

namespace App\Support;

use App\Models\CustomerLoan;
use App\Models\CustomerLoanRepayment;
use App\Models\CustomerOrderItem;
use App\Models\FactoryProduct;
use App\Models\Sale;
use App\Models\SaleItem;
use App\Models\SalePack;
use App\Models\SalePayment;
use App\Models\StockMovement;
use Illuminate\Support\Facades\DB;

class ClearCustomerLedgerAndPaymentsData
{
    /**
     * @return list<string>
     */
    private static function saleStockMovementTypes(): array
    {
        return [
            StockMovementType::SALE_OUT,
            StockMovementType::SALE_RETURN_IN,
            StockMovementType::SALE_RETURN_DEFECTIVE,
            StockMovementType::SALE_RETURN_EXPIRED,
        ];
    }

    /**
     * Remove all customer ledger activity: sales (bills), payments, and cash loans.
     * Customers are kept; finished-goods stock is recalculated from remaining movements.
     *
     * @return array{
     *     sales: int,
     *     sale_items: int,
     *     sale_packs: int,
     *     sale_payments: int,
     *     sale_stock_movements: int,
     *     order_items_reset: int,
     *     loan_repayments: int,
     *     loans: int,
     * }
     */
    public static function run(): array
    {
        return DB::transaction(function (): array {
            $counts = [
                'sales' => Sale::query()->count(),
                'sale_items' => SaleItem::query()->count(),
                'sale_packs' => SalePack::query()->count(),
                'sale_payments' => SalePayment::query()->count(),
                'sale_stock_movements' => StockMovement::query()
                    ->whereIn('movement_type', self::saleStockMovementTypes())
                    ->count(),
                'order_items_reset' => CustomerOrderItem::query()
                    ->where('sold_quantity', '>', 0)
                    ->count(),
                'loan_repayments' => CustomerLoanRepayment::query()->count(),
                'loans' => CustomerLoan::query()->count(),
            ];

            SalePack::query()->update(['original_sale_pack_id' => null]);
            SalePayment::query()->delete();
            SalePack::query()->delete();
            SaleItem::query()->delete();
            Sale::query()->delete();

            StockMovement::query()
                ->whereIn('movement_type', self::saleStockMovementTypes())
                ->delete();

            CustomerOrderItem::query()->update(['sold_quantity' => 0]);

            CustomerLoanRepayment::query()->delete();
            CustomerLoan::query()->delete();

            self::recalculateFinishedGoodsStockFromMovements();

            return $counts;
        });
    }

    private static function recalculateFinishedGoodsStockFromMovements(): void
    {
        $productIds = FactoryProduct::query()->pluck('id');

        foreach ($productIds as $productId) {
            $saleableQuantity = (float) StockMovement::query()
                ->where('kind', StockKind::FINISHED_GOODS)
                ->where('product_id', $productId)
                ->whereIn('movement_type', [
                    StockMovementType::PRODUCTION_IN,
                    StockMovementType::SALE_OUT,
                    StockMovementType::SALE_RETURN_IN,
                    StockMovementType::STAFF_ADVANCE_OUT,
                    StockMovementType::STAFF_ADVANCE_RESTORE,
                ])
                ->sum('quantity');

            $defectiveQuantity = (float) StockMovement::query()
                ->where('kind', StockKind::FINISHED_GOODS)
                ->where('product_id', $productId)
                ->where('movement_type', StockMovementType::SALE_RETURN_DEFECTIVE)
                ->sum('quantity');

            $expiredQuantity = (float) StockMovement::query()
                ->where('kind', StockKind::FINISHED_GOODS)
                ->where('product_id', $productId)
                ->where('movement_type', StockMovementType::SALE_RETURN_EXPIRED)
                ->sum('quantity');

            FactoryProduct::query()
                ->whereKey($productId)
                ->update([
                    'stock_on_hand' => round(max(0, $saleableQuantity), 3),
                    'defective_stock' => round(max(0, $defectiveQuantity), 3),
                    'expired_stock' => round(max(0, $expiredQuantity), 3),
                ]);
        }
    }
}
