<?php

namespace App\Services;

use App\Models\FixedAsset;
use App\Models\FixedAssetDepreciation;
use Illuminate\Support\Collection;

class FixedAssetDepreciationService
{
    public function scheduleForPeriod(int $companyId, int $year, int $month): Collection
    {
        return FixedAsset::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->where('is_active', true)
            ->where('status', 'active')
            ->with(['category', 'assetAccount', 'accumDepreciationAccount', 'depreciationExpenseAccount'])
            ->orderBy('code')
            ->get()
            ->map(function (FixedAsset $asset) use ($companyId, $year, $month) {
                $alreadyPosted = FixedAssetDepreciation::withoutGlobalScopes()
                    ->where('company_id', $companyId)
                    ->where('fixed_asset_id', $asset->id)
                    ->where('period_year', $year)
                    ->where('period_month', $month)
                    ->exists();

                $proposed = $this->proposedAmount($asset);

                return [
                    'asset'          => $asset,
                    'proposed'       => $proposed,
                    'book_value'     => $asset->bookValue(),
                    'already_posted' => $alreadyPosted,
                    'can_post'       => !$alreadyPosted && $proposed > 0 && $asset->status === 'active',
                ];
            });
    }

    public function run(int $companyId, int $year, int $month, ?array $assetIds = null): array
    {
        $query = FixedAsset::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->where('is_active', true)
            ->where('status', 'active');

        if ($assetIds !== null && $assetIds !== []) {
            $query->whereIn('id', $assetIds);
        }

        $posted = 0;
        $skipped = 0;
        $totalAmount = 0.0;

        foreach ($query->get() as $asset) {
            $exists = FixedAssetDepreciation::withoutGlobalScopes()
                ->where('company_id', $companyId)
                ->where('fixed_asset_id', $asset->id)
                ->where('period_year', $year)
                ->where('period_month', $month)
                ->exists();

            if ($exists) {
                $skipped++;
                continue;
            }

            $amount = $this->proposedAmount($asset);
            if ($amount <= 0) {
                $skipped++;
                continue;
            }

            FixedAssetDepreciation::withoutGlobalScopes()->create([
                'company_id'     => $companyId,
                'fixed_asset_id' => $asset->id,
                'period_year'    => $year,
                'period_month'   => $month,
                'amount'         => $amount,
                'posted_at'      => now(),
            ]);

            $newAccum = round((float) $asset->accumulated_depreciation + $amount, 2);
            $status = $newAccum >= $asset->depreciableAmount() ? 'fully_depreciated' : 'active';

            $asset->update([
                'accumulated_depreciation' => $newAccum,
                'status'                   => $status,
            ]);

            $posted++;
            $totalAmount = round($totalAmount + $amount, 2);
        }

        return [
            'posted'       => $posted,
            'skipped'      => $skipped,
            'total_amount' => $totalAmount,
        ];
    }

    public function proposedAmount(FixedAsset $asset): float
    {
        if ($asset->status !== 'active') {
            return 0.0;
        }

        $monthly = $asset->monthlyDepreciation();
        if ($monthly <= 0) {
            return 0.0;
        }

        return round(min($monthly, $asset->bookValue()), 2);
    }
}
