<?php
declare(strict_types=1);

namespace App\Modules\Inventory\Services;

use App\Core\App;
use App\Core\EventBus;

final class BomService
{
    public static function create(array $data, array $components): array
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        $bomCode = $data['bom_code'] ?? ('BOM-' . str_pad((string) random_int(1, 99999), 5, '0', STR_PAD_LEFT));

        $db->beginTransaction();
        try {
            $bomId = $db->insert('bill_of_materials', [
                'item_id' => (int) $data['item_id'],
                'bom_code' => $bomCode,
                'version' => (int) ($data['version'] ?? 1),
                'name_ar' => $data['name_ar'],
                'name_en' => $data['name_en'] ?? null,
                'output_quantity' => $data['output_quantity'] ?? '1.000',
                'notes' => $data['notes'] ?? null,
                'created_by' => $employee ? (int) $employee->id : null,
            ]);

            foreach ($components as $i => $comp) {
                $db->insert('bom_components', [
                    'bom_id' => $bomId,
                    'component_item_id' => (int) $comp['item_id'],
                    'quantity' => $comp['quantity'],
                    'unit' => $comp['unit'] ?? null,
                    'waste_percentage' => $comp['waste_percentage'] ?? '0.00',
                    'is_optional' => (int) ($comp['is_optional'] ?? 0),
                    'sort_order' => $i + 1,
                    'notes' => $comp['notes'] ?? null,
                ]);
            }

            $db->commit();

            EventBus::dispatch('bom.created', ['bom_id' => $bomId, 'item_id' => (int) $data['item_id']]);

            return ['success' => true, 'bom_id' => $bomId, 'bom_code' => $bomCode];
        } catch (\Throwable $e) {
            $db->rollBack();
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }

    public static function deductComponents(int $bomId, string $quantity, int $warehouseId): array
    {
        $db = App::getInstance()->db();

        $bom = $db->selectOne("SELECT * FROM bill_of_materials WHERE id = ? AND is_active = 1", [$bomId]);
        if (!$bom) {
            return ['success' => false, 'error' => 'قائمة المواد غير موجودة'];
        }

        $components = $db->select("SELECT * FROM bom_components WHERE bom_id = ?", [$bomId]);
        $multiplier = bcdiv($quantity, (string) $bom['output_quantity'], 6);

        $insufficientItems = [];
        foreach ($components as $comp) {
            if ($comp['is_optional']) continue;

            $requiredQty = bcmul((string) $comp['quantity'], $multiplier, 3);
            $wasteQty = bcmul($requiredQty, bcdiv((string) $comp['waste_percentage'], '100', 6), 3);
            $totalRequired = bcadd($requiredQty, $wasteQty, 3);

            $stock = $db->selectOne(
                "SELECT quantity FROM item_warehouse_stock WHERE item_id = ? AND warehouse_id = ?",
                [(int) $comp['component_item_id'], $warehouseId]
            );

            $available = (string) ($stock['quantity'] ?? '0');
            if (bccomp($available, $totalRequired, 3) < 0) {
                $item = $db->selectOne("SELECT name_ar FROM inventory_items WHERE id = ?", [(int) $comp['component_item_id']]);
                $insufficientItems[] = ($item['name_ar'] ?? '#' . $comp['component_item_id']) . " (مطلوب: {$totalRequired}, متاح: {$available})";
            }
        }

        if (!empty($insufficientItems)) {
            return ['success' => false, 'error' => 'مخزون غير كافٍ: ' . implode(', ', $insufficientItems)];
        }

        $db->beginTransaction();
        try {
            foreach ($components as $comp) {
                if ($comp['is_optional']) continue;

                $requiredQty = bcmul((string) $comp['quantity'], $multiplier, 3);
                $wasteQty = bcmul($requiredQty, bcdiv((string) $comp['waste_percentage'], '100', 6), 3);
                $totalRequired = bcadd($requiredQty, $wasteQty, 3);

                StockService::moveStock([
                    'item_id' => (int) $comp['component_item_id'],
                    'warehouse_id' => $warehouseId,
                    'movement_type' => 'consumed_out',
                    'direction' => 'out',
                    'quantity' => $totalRequired,
                    'reference_type' => 'bill_of_materials',
                    'reference_id' => $bomId,
                    'notes' => 'خصم مكونات BOM: ' . $bom['bom_code'] . ' × ' . $quantity,
                ]);
            }

            $db->commit();

            EventBus::dispatch('bom.components_deducted', [
                'bom_id' => $bomId,
                'quantity' => $quantity,
                'warehouse_id' => $warehouseId,
            ]);

            return ['success' => true];
        } catch (\Throwable $e) {
            $db->rollBack();
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }

    public static function calculateCost(int $bomId): array
    {
        $db = App::getInstance()->db();

        $bom = $db->selectOne("SELECT * FROM bill_of_materials WHERE id = ?", [$bomId]);
        if (!$bom) return ['total_cost' => '0.00', 'components' => []];

        $components = $db->select(
            "SELECT bc.*, i.name_ar, i.selling_price,
                    (SELECT AVG(unit_cost) FROM stock_movements WHERE item_id = bc.component_item_id AND direction = 'in' ORDER BY created_at DESC LIMIT 10) as avg_cost
             FROM bom_components bc
             JOIN inventory_items i ON i.id = bc.component_item_id
             WHERE bc.bom_id = ?
             ORDER BY bc.sort_order",
            [$bomId]
        );

        $totalCost = '0.00';
        $details = [];
        foreach ($components as $comp) {
            $unitCost = (string) ($comp['avg_cost'] ?? $comp['selling_price'] ?? '0');
            $componentCost = bcmul($unitCost, (string) $comp['quantity'], 2);
            $totalCost = bcadd($totalCost, $componentCost, 2);

            $details[] = [
                'item_id' => (int) $comp['component_item_id'],
                'name' => $comp['name_ar'],
                'quantity' => $comp['quantity'],
                'unit_cost' => $unitCost,
                'total_cost' => $componentCost,
            ];
        }

        $costPerUnit = bccomp((string) $bom['output_quantity'], '0', 3) > 0
            ? bcdiv($totalCost, (string) $bom['output_quantity'], 2)
            : $totalCost;

        return ['total_cost' => $totalCost, 'cost_per_unit' => $costPerUnit, 'components' => $details];
    }

    public static function getBomForItem(int $itemId): ?array
    {
        $db = App::getInstance()->db();
        return $db->selectOne("SELECT * FROM bill_of_materials WHERE item_id = ? AND is_active = 1 ORDER BY version DESC LIMIT 1", [$itemId]);
    }
}
