<?php
declare(strict_types=1);

namespace App\Modules\Sales\Services;

use App\Core\App;
use App\Core\EventBus;
use App\Core\Logger;
use App\Modules\Inventory\Services\StockService;

final class RefundService
{
    /**
     * Process a refund for a sale.
     *
     * @param int    $saleId
     * @param string $amount        Refund amount
     * @param string $reason        Refund reason
     * @param bool   $returnToStock Whether to return items to stock
     * @param array  $refundItems   Items to refund: [['sale_item_id' => int, 'quantity' => string], ...]
     */
    public static function processRefund(int $saleId, string $amount, string $reason, bool $returnToStock, array $refundItems = []): array
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        $sale = $db->selectOne("SELECT * FROM `sales` WHERE `id` = ?", [$saleId]);
        if (!$sale) {
            return ['success' => false, 'error' => 'المبيعة غير موجودة'];
        }
        if (in_array($sale['status'], ['voided', 'fully_refunded'], true)) {
            return ['success' => false, 'error' => 'لا يمكن استرجاع هذه المبيعة'];
        }

        $maxRefund = bcsub((string) $sale['total_amount'], (string) $sale['amount_refunded'], 2);
        if (bccomp($amount, $maxRefund, 2) > 0) {
            return ['success' => false, 'error' => 'مبلغ الاسترجاع أكبر من المتبقي — الحد الأقصى: ' . $maxRefund];
        }

        $refundNumber = InvoiceNumberGenerator::nextRefundNumber();
        $warehouseId = (int) $sale['warehouse_id'];

        $db->beginTransaction();
        try {
            $refundId = $db->insert('sale_refunds', [
                'sale_id'         => $saleId,
                'refund_number'   => $refundNumber,
                'refund_amount'   => $amount,
                'reason'          => $reason,
                'return_to_stock' => $returnToStock ? 1 : 0,
                'warehouse_id'    => $returnToStock ? $warehouseId : null,
                'refunded_by'     => $employee ? (int) $employee->id : null,
                'refund_date'     => date('Y-m-d'),
                'created_by'      => $employee ? (int) $employee->id : null,
                'created_at'      => date('Y-m-d H:i:s'),
            ]);

            // Return stock if requested
            if ($returnToStock && !empty($refundItems)) {
                foreach ($refundItems as $ri) {
                    $saleItem = $db->selectOne("SELECT * FROM `sale_items` WHERE `id` = ?", [(int) $ri['sale_item_id']]);
                    if (!$saleItem || !$saleItem['item_id']) continue;

                    $refQty = (string) $ri['quantity'];

                    StockService::moveStock([
                        'item_id'        => (int) $saleItem['item_id'],
                        'warehouse_id'   => $warehouseId,
                        'movement_type'  => 'return_in',
                        'direction'      => 'in',
                        'quantity'       => $refQty,
                        'reference_type' => 'sale_refunds',
                        'reference_id'   => $refundId,
                        'notes'          => 'مرتجع مبيعات — ' . $refundNumber,
                    ]);

                    // Update sale item refunded tracking
                    $newRefQty = bcadd((string) $saleItem['refunded_quantity'], $refQty, 3);
                    $isFullyRefunded = bccomp($newRefQty, (string) $saleItem['quantity'], 3) >= 0 ? 1 : 0;

                    $db->update('sale_items', [
                        'refunded_quantity' => $newRefQty,
                        'is_refunded'       => $isFullyRefunded,
                    ], '`id` = ?', [(int) $saleItem['id']]);
                }
            }

            // Update sale totals
            $newRefundedTotal = bcadd((string) $sale['amount_refunded'], $amount, 2);
            $isFullyRefunded = bccomp($newRefundedTotal, (string) $sale['total_amount'], 2) >= 0;

            $db->update('sales', [
                'amount_refunded' => $newRefundedTotal,
                'status'          => $isFullyRefunded ? 'fully_refunded' : 'partially_refunded',
                'updated_at'      => date('Y-m-d H:i:s'),
            ], '`id` = ?', [$saleId]);

            $db->commit();
        } catch (\Throwable $e) {
            $db->rollBack();
            return ['success' => false, 'error' => 'فشل الاسترجاع: ' . $e->getMessage()];
        }

        EventBus::dispatch('sale.refunded', [
            'sale_id'       => $saleId,
            'refund_id'     => $refundId,
            'refund_number' => $refundNumber,
            'amount'        => $amount,
        ]);

        Logger::info("Refund #{$refundId} ({$refundNumber}) for sale #{$saleId} — amount: {$amount}");

        return [
            'success'       => true,
            'refund_id'     => $refundId,
            'refund_number' => $refundNumber,
        ];
    }
}
