<?php
declare(strict_types=1);

namespace App\Modules\Inventory\Services;

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

final class DepreciationService
{
    /**
     * Run monthly depreciation for all active assets.
     *
     * @param string $periodMonth  YYYY-MM format
     * @return int Number of assets depreciated
     */
    public static function runMonthlyDepreciation(string $periodMonth): int
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();
        $count = 0;

        $assets = $db->select(
            "SELECT * FROM `asset_register` WHERE `status` = 'active'"
        );

        foreach ($assets as $asset) {
            // Skip if already depreciated for this period
            $existing = $db->selectOne(
                "SELECT `id` FROM `depreciation_entries` WHERE `asset_id` = ? AND `period_month` = ?",
                [(int) $asset['id'], $periodMonth]
            );
            if ($existing) continue;

            // Skip if book value already at salvage
            $bookValue = (string) $asset['book_value'];
            $salvageValue = (string) $asset['salvage_value'];
            if (bccomp($bookValue, $salvageValue, 2) <= 0) continue;

            // Calculate depreciation amount
            $depAmount = self::calculateDepreciation($asset);

            // Ensure book value doesn't go below salvage
            $maxDep = bcsub($bookValue, $salvageValue, 2);
            if (bccomp($depAmount, $maxDep, 2) > 0) {
                $depAmount = $maxDep;
            }

            if (bccomp($depAmount, '0.00', 2) <= 0) continue;

            $newAccumulated = bcadd((string) $asset['accumulated_depreciation'], $depAmount, 2);
            $newBookValue = bcsub($bookValue, $depAmount, 2);

            $db->beginTransaction();
            try {
                $db->insert('depreciation_entries', [
                    'asset_id'            => (int) $asset['id'],
                    'period_month'        => $periodMonth,
                    'depreciation_amount' => $depAmount,
                    'accumulated_total'   => $newAccumulated,
                    'book_value_after'    => $newBookValue,
                    'method_used'         => $asset['depreciation_method'],
                    'is_manual'           => 0,
                    'created_by'          => $employee ? (int) $employee->id : null,
                    'created_at'          => date('Y-m-d H:i:s'),
                ]);

                $db->update('asset_register', [
                    'accumulated_depreciation' => $newAccumulated,
                    'book_value'               => $newBookValue,
                    'last_depreciation_date'   => $periodMonth . '-01',
                    'updated_at'               => date('Y-m-d H:i:s'),
                ], '`id` = ?', [(int) $asset['id']]);

                $db->commit();
                $count++;
            } catch (\Throwable $e) {
                $db->rollBack();
                Logger::error("Depreciation failed for asset #{$asset['id']}: " . $e->getMessage());
            }
        }

        if ($count > 0) {
            EventBus::dispatch('inventory.depreciation_run', [
                'period_month' => $periodMonth,
                'assets_count' => $count,
            ]);

            Logger::info("Monthly depreciation for {$periodMonth}: {$count} asset(s) processed");
        }

        return $count;
    }

    /**
     * Calculate monthly depreciation for an asset.
     */
    private static function calculateDepreciation(array $asset): string
    {
        $method = $asset['depreciation_method'] ?? 'straight_line';

        if ($method === 'straight_line') {
            // Monthly = (Purchase Cost - Salvage Value) / Useful Life in Months
            $depreciableBase = bcsub((string) $asset['purchase_cost'], (string) $asset['salvage_value'], 2);
            $months = max(1, (int) ($asset['useful_life_months'] ?? 60));
            return bcdiv($depreciableBase, (string) $months, 2);
        }

        if ($method === 'declining_balance') {
            // Monthly = Book Value × Annual Rate / 12
            $rate = (float) ($asset['declining_rate'] ?? 20.00);
            $annualDep = bcmul((string) $asset['book_value'], (string) ($rate / 100), 2);
            return bcdiv($annualDep, '12', 2);
        }

        return '0.00';
    }
}
