<?php

namespace App\Http\Controllers\Admin\Accounting;

use App\Http\Controllers\Admin\PageController;
use App\Models\Account;
use App\Models\FixedAsset;
use App\Services\Accounting\FixedAssetService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Illuminate\View\View;

class FixedAssetController extends PageController
{
    public function __construct(
        private readonly FixedAssetService $fixedAssetService,
    ) {}

    public function index(): View
    {
        $assets = FixedAsset::query()
            ->with(['assetAccount', 'depreciationAccount'])
            ->orderBy('asset_code')
            ->paginate(20);

        return $this->page('admin.fixed-assets.index', [
            'crumbTitle' => 'Fixed Assets Register',
            'crumbSub' => 'Buildings, vehicles & equipment with depreciation',
            'assets' => $assets,
        ]);
    }

    public function create(): View
    {
        return $this->page('admin.fixed-assets.create', [
            'crumbTitle' => 'Fixed Assets Register',
            'crumbSub' => 'Register new asset',
            'assetAccounts' => Account::query()->where('account_type', 'fixed_asset')->orderBy('code')->get(),
            'depreciationAccounts' => Account::query()->where('account_type', 'contra_asset')->orderBy('code')->get(),
        ]);
    }

    public function store(Request $request): RedirectResponse
    {
        $validated = $this->validateAsset($request);

        $purchaseCost = number_format((float) $validated['purchase_cost'], 2, '.', '');

        FixedAsset::query()->create([
            ...$validated,
            'book_value' => $purchaseCost,
        ]);

        return $this->redirectWithSuccess('accounting.fixed-assets.index', 'Fixed asset registered successfully.');
    }

    public function edit(FixedAsset $fixedAsset): View
    {
        return $this->page('admin.fixed-assets.edit', [
            'crumbTitle' => 'Fixed Assets Register',
            'crumbSub' => 'Edit '.$fixedAsset->asset_code,
            'asset' => $fixedAsset,
            'assetAccounts' => Account::query()->where('account_type', 'fixed_asset')->orderBy('code')->get(),
            'depreciationAccounts' => Account::query()->where('account_type', 'contra_asset')->orderBy('code')->get(),
        ]);
    }

    public function update(Request $request, FixedAsset $fixedAsset): RedirectResponse
    {
        $validated = $this->validateAsset($request, $fixedAsset);

        $fixedAsset->update($validated);

        return $this->redirectWithSuccess('accounting.fixed-assets.index', 'Fixed asset updated successfully.');
    }

    public function depreciate(FixedAsset $fixedAsset): RedirectResponse
    {
        try {
            $this->fixedAssetService->runDepreciation($fixedAsset);
        } catch (\Throwable $e) {
            return back()->with('error', $e->getMessage());
        }

        return back()->with('success', 'Depreciation posted successfully.');
    }

    /**
     * @return array<string, mixed>
     */
    private function validateAsset(Request $request, ?FixedAsset $asset = null): array
    {
        return $request->validate([
            'asset_code' => [
                'required',
                'string',
                'max:50',
                Rule::unique('fixed_assets', 'asset_code')->ignore($asset?->id),
            ],
            'name' => ['required', 'string', 'max:255'],
            'category' => ['nullable', 'string', 'max:100'],
            'purchase_date' => ['nullable', 'date'],
            'purchase_cost' => ['required', 'numeric', 'min:0'],
            'salvage_value' => ['nullable', 'numeric', 'min:0'],
            'useful_life_months' => ['nullable', 'integer', 'min:1'],
            'depreciation_method' => ['nullable', 'string', 'max:100'],
            'asset_account_id' => ['nullable', 'exists:accounts,id'],
            'depreciation_account_id' => ['nullable', 'exists:accounts,id'],
            'location' => ['nullable', 'string', 'max:255'],
            'serial_number' => ['nullable', 'string', 'max:100'],
            'status' => ['nullable', 'string', 'max:50'],
            'notes' => ['nullable', 'string'],
        ]);
    }
}
