<?php
declare(strict_types=1);

namespace App\Modules\Inventory\Services;

use App\Core\App;
use App\Core\EventBus;
use App\Core\Logger;
use App\Modules\Inventory\Models\StockTransfer;
use App\Modules\Inventory\Models\StockTransferItem;

final class StockTransferService
{
    /**
     * Create a new transfer with its items.
     *
     * @param array $header  Keys: from_warehouse_id, to_warehouse_id, transfer_date, notes
     * @param array $items   Each: ['item_id' => int, 'quantity' => string, 'batch_id' => ?int, 'notes' => ?string]
     * @return int transfer ID
     */
    public static function createTransfer(array $header, array $items): int
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        if (empty($items)) {
            throw new \RuntimeException('يجب إضافة صنف واحد على الأقل');
        }

        $fromId = (int) ($header['from_warehouse_id'] ?? 0);
        $toId = (int) ($header['to_warehouse_id'] ?? 0);

        if ($fromId <= 0 || $toId <= 0) {
            throw new \RuntimeException('يجب تحديد المخزن المصدر والمخزن المستقبل');
        }
        if ($fromId === $toId) {
            throw new \RuntimeException('لا يمكن التحويل لنفس المخزن');
        }

        $transferNumber = InventoryNumberGenerator::nextTransferNumber();

        $db->beginTransaction();
        try {
            $transferId = $db->insert('stock_transfers', [
                'transfer_number'   => $transferNumber,
                'from_warehouse_id' => $fromId,
                'to_warehouse_id'   => $toId,
                'status'            => 'pending_approval',
                'requested_by'      => $employee ? (int) $employee->id : null,
                'transfer_date'     => $header['transfer_date'] ?? date('Y-m-d'),
                'notes'             => $header['notes'] ?? null,
                'created_by'        => $employee ? (int) $employee->id : null,
                'created_at'        => date('Y-m-d H:i:s'),
                'updated_at'        => date('Y-m-d H:i:s'),
            ]);

            foreach ($items as $item) {
                $db->insert('stock_transfer_items', [
                    'transfer_id' => $transferId,
                    'item_id'     => (int) $item['item_id'],
                    'quantity'    => $item['quantity'],
                    'batch_id'    => isset($item['batch_id']) ? (int) $item['batch_id'] : null,
                    'notes'       => $item['notes'] ?? null,
                ]);
            }

            $db->commit();
        } catch (\Throwable $e) {
            $db->rollBack();
            throw $e;
        }

        Logger::info("Transfer #{$transferId} ({$transferNumber}) created: warehouse #{$fromId} → #{$toId}");

        return $transferId;
    }

    /**
     * Approve a pending transfer.
     */
    public static function approve(int $transferId): void
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        $transfer = $db->selectOne("SELECT * FROM `stock_transfers` WHERE `id` = ?", [$transferId]);
        if (!$transfer) {
            throw new \RuntimeException('التحويل غير موجود');
        }
        if ($transfer['status'] !== 'pending_approval') {
            throw new \RuntimeException('التحويل ليس في حالة انتظار الموافقة');
        }

        $db->update('stock_transfers', [
            'status'      => 'approved',
            'approved_by' => $employee ? (int) $employee->id : null,
            'approved_at' => date('Y-m-d H:i:s'),
            'updated_at'  => date('Y-m-d H:i:s'),
        ], '`id` = ?', [$transferId]);

        Logger::info("Transfer #{$transferId} approved");
    }

    /**
     * Receive a transfer — executes all stock movements.
     */
    public static function receive(int $transferId): void
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        $transfer = $db->selectOne("SELECT * FROM `stock_transfers` WHERE `id` = ?", [$transferId]);
        if (!$transfer) {
            throw new \RuntimeException('التحويل غير موجود');
        }
        if (!in_array($transfer['status'], ['approved', 'in_transit'], true)) {
            throw new \RuntimeException('التحويل ليس في حالة تسمح بالاستلام');
        }

        $items = StockTransferItem::getForTransfer($transferId);
        if (empty($items)) {
            throw new \RuntimeException('التحويل لا يحتوي على أصناف');
        }

        $fromWarehouse = (int) $transfer['from_warehouse_id'];
        $toWarehouse = (int) $transfer['to_warehouse_id'];

        $db->beginTransaction();
        try {
            foreach ($items as $item) {
                // OUT from source warehouse
                StockService::moveStock([
                    'item_id'        => (int) $item['item_id'],
                    'warehouse_id'   => $fromWarehouse,
                    'movement_type'  => 'transfer_out',
                    'direction'      => 'out',
                    'quantity'       => (string) $item['quantity'],
                    'batch_id'       => $item['batch_id'] ? (int) $item['batch_id'] : null,
                    'reference_type' => 'stock_transfers',
                    'reference_id'   => $transferId,
                    'transfer_id'    => $transferId,
                    'notes'          => 'تحويل صادر — ' . $transfer['transfer_number'],
                ]);

                // IN to destination warehouse
                StockService::moveStock([
                    'item_id'        => (int) $item['item_id'],
                    'warehouse_id'   => $toWarehouse,
                    'movement_type'  => 'transfer_in',
                    'direction'      => 'in',
                    'quantity'       => (string) $item['quantity'],
                    'batch_id'       => $item['batch_id'] ? (int) $item['batch_id'] : null,
                    'reference_type' => 'stock_transfers',
                    'reference_id'   => $transferId,
                    'transfer_id'    => $transferId,
                    'notes'          => 'تحويل وارد — ' . $transfer['transfer_number'],
                ]);
            }

            $db->update('stock_transfers', [
                'status'      => 'received',
                'received_by' => $employee ? (int) $employee->id : null,
                'received_at' => date('Y-m-d H:i:s'),
                'updated_at'  => date('Y-m-d H:i:s'),
            ], '`id` = ?', [$transferId]);

            $db->commit();
        } catch (\Throwable $e) {
            $db->rollBack();
            throw $e;
        }

        EventBus::dispatch('inventory.transfer_completed', [
            'transfer_id'      => $transferId,
            'from_warehouse_id' => $fromWarehouse,
            'to_warehouse_id'   => $toWarehouse,
        ]);

        Logger::info("Transfer #{$transferId} received: all stock movements executed");
    }
}
