<?php

namespace App\Services;

use App\Models\InventoryOpening;
use App\Models\InventoryOpeningItem;
use App\Services\InventoryService;
use App\Services\DocumentSequenceService;
use App\Services\AuditLogService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class OpeningStockService
{
    protected InventoryService $inventoryService;
    protected DocumentSequenceService $sequenceService;
    protected AuditLogService $auditService;
    protected BranchAccessService $branches;

    public function __construct(
        InventoryService $inventoryService,
        DocumentSequenceService $sequenceService,
        AuditLogService $auditService,
        BranchAccessService $branches
    ) {
        $this->inventoryService = $inventoryService;
        $this->sequenceService  = $sequenceService;
        $this->auditService     = $auditService;
        $this->branches         = $branches;
    }

    /**
     * Create a draft opening stock entry.
     */
    public function createDraft(array $header, array $items): InventoryOpening
    {
        return DB::transaction(function () use ($header, $items) {
            $this->branches->assertWarehouse((int) $header['warehouse_id'], null, 'inventory');
            $refNo = $this->sequenceService->getNextNumber('OPENING_STOCK')
                ?? ('OS-' . now()->format('ymd') . '-' . rand(1000, 9999));

            $totalCost = collect($items)->reduce(fn ($total, $item) => bcadd($total, (string) ($item['total_cost'] ?? 0), 4), '0.0000');

            $opening = InventoryOpening::create([
                'reference_no'     => $refNo,
                'opening_date'     => $header['opening_date'],
                'warehouse_id'     => $header['warehouse_id'],
                'financial_year_id'=> $header['financial_year_id'],
                'notes'            => $header['notes'] ?? null,
                'status'           => 'draft',
                'total_cost'       => $totalCost,
                'created_by'       => Auth::id(),
            ]);

            foreach ($items as $item) {
                InventoryOpeningItem::create([
                    'opening_id'   => $opening->id,
                    'product_id'   => $item['product_id'],
                    'unit_id'      => $item['unit_id'],
                    'qty'          => $item['qty'],
                    'base_qty'     => $item['base_qty'],
                    'unit_cost'    => $item['unit_cost'],
                    'total_cost'   => $item['total_cost'],
                    'batch_number' => $item['batch_number'] ?? null,
                    'expiry_date'  => $item['expiry_date'] ?? null,
                ]);
            }

            $this->auditService->log('OPENING_STOCK_CREATED', 'inventory_openings', $opening->id, null, ['reference' => $refNo]);

            return $opening;
        });
    }

    /**
     * Approve opening stock – posts to stock_ledger and updates warehouse_stocks.
     * MUST use DB::transaction for full atomicity.
     */
    public function approve(InventoryOpening $opening): void
    {
        $this->branches->assertWarehouse((int) $opening->warehouse_id, null, 'inventory');
        if ($opening->status !== 'draft') {
            throw new \RuntimeException('Only draft opening stock can be approved.');
        }

        DB::transaction(function () use ($opening) {
            $opening->load('items.product');

            foreach ($opening->items as $item) {
                $this->inventoryService->stockIn([
                    'transaction_date'  => $opening->opening_date,
                    'transaction_type'  => 'OPENING_STOCK',
                    'reference_type'    => 'inventory_openings',
                    'reference_id'      => $opening->id,
                    'reference_number'  => $opening->reference_no,
                    'product_id'        => $item->product_id,
                    'warehouse_id'      => $opening->warehouse_id,
                    'unit_id'           => $item->unit_id,
                    'qty_in'            => (float)$item->qty,
                    'base_qty_in'       => (float)$item->base_qty,
                    'unit_cost'         => (float)$item->unit_cost,
                    'batch_number'      => $item->batch_number,
                    'expiry'            => $item->expiry_date,
                    'financial_year_id' => $opening->financial_year_id,
                    'created_by'        => Auth::id(),
                ]);
            }

            $opening->status      = 'approved';
            $opening->approved_by = Auth::id();
            $opening->approved_at = now();
            $opening->save();

            $this->auditService->log('OPENING_STOCK_APPROVED', 'inventory_openings', $opening->id, ['status' => 'draft'], ['status' => 'approved']);
        });
    }
}
