<?php

namespace Modules\Accounting\Services;

use App\Models\ActivityLogModel;
use App\Models\AssetCategoryModel;
use App\Models\AssetDisposalModel;
use App\Models\DepreciationRunLineModel;
use App\Models\FixedAssetModel;

class FixedAssetService
{
    protected FixedAssetModel $assets;
    protected AssetCategoryModel $categories;
    protected DepreciationRunLineModel $runLines;
    protected AssetDisposalModel $disposals;
    protected ActivityLogModel $activity;

    public function __construct()
    {
        $this->assets     = new FixedAssetModel();
        $this->categories = new AssetCategoryModel();
        $this->runLines   = new DepreciationRunLineModel();
        $this->disposals  = new AssetDisposalModel();
        $this->activity   = new ActivityLogModel();
    }

    public function create(array $input, ?int $actingUserId): array
    {
        $categoryId = (int) ($input['category_id'] ?? 0);
        $category = $this->categories->find($categoryId);
        if (! $category) {
            return ['success' => false, 'errors' => ['category_id' => 'Asset category not found.']];
        }

        $cost = round((float) ($input['cost'] ?? 0), 2);
        if ($cost <= 0) {
            return ['success' => false, 'errors' => ['cost' => 'Cost must be greater than zero.']];
        }

        $usefulLife = ! empty($input['useful_life_months'])
            ? (int) $input['useful_life_months']
            : (int) $category['useful_life_months'];

        $salvage = isset($input['salvage_value']) && $input['salvage_value'] !== ''
            ? round((float) $input['salvage_value'], 2)
            : round($cost * ((float) $category['salvage_percent'] / 100), 2);

        $data = $this->mapInput($input);
        $data['number']              = $this->assets->nextNumber();
        $data['cost']                = $cost;
        $data['salvage_value']       = $salvage;
        $data['useful_life_months']  = $usefulLife > 0 ? $usefulLife : null;
        $data['accum_depreciation']  = 0.00;
        $data['book_value']          = $cost;
        $data['status']              = 'active';
        $data['created_by']          = $actingUserId;
        $data['updated_by']          = $actingUserId;

        if (! $this->assets->insert($data, true)) {
            return ['success' => false, 'errors' => $this->assets->errors()];
        }

        $id = (int) $this->assets->getInsertID();
        $this->activity->log('fixed_assets', 'created', $actingUserId, "Created fixed asset #{$id} ({$data['number']})", (string) $id);

        return ['success' => true, 'id' => $id];
    }

    public function update(int $id, array $input, ?int $actingUserId): array
    {
        $asset = $this->assets->find($id);
        if (! $asset) {
            return ['success' => false, 'errors' => ['id' => 'Fixed asset not found.']];
        }
        if ($asset['status'] !== 'active') {
            return ['success' => false, 'errors' => ['status' => 'Only active assets can be edited.']];
        }
        if ($this->runLines->hasPostedForAsset($id)) {
            return ['success' => false, 'errors' => ['status' => 'Cannot edit an asset that has posted depreciation.']];
        }

        $categoryId = (int) ($input['category_id'] ?? 0);
        $category = $this->categories->find($categoryId);
        if (! $category) {
            return ['success' => false, 'errors' => ['category_id' => 'Asset category not found.']];
        }

        $cost = round((float) ($input['cost'] ?? 0), 2);
        if ($cost <= 0) {
            return ['success' => false, 'errors' => ['cost' => 'Cost must be greater than zero.']];
        }

        $usefulLife = ! empty($input['useful_life_months'])
            ? (int) $input['useful_life_months']
            : (int) $category['useful_life_months'];

        $salvage = isset($input['salvage_value']) && $input['salvage_value'] !== ''
            ? round((float) $input['salvage_value'], 2)
            : round($cost * ((float) $category['salvage_percent'] / 100), 2);

        $data = $this->mapInput($input);
        $data['cost']               = $cost;
        $data['salvage_value']      = $salvage;
        $data['useful_life_months'] = $usefulLife > 0 ? $usefulLife : null;
        $data['book_value']         = $cost;
        $data['accum_depreciation'] = 0.00;
        $data['updated_by']         = $actingUserId;

        if (! $this->assets->update($id, $data)) {
            return ['success' => false, 'errors' => $this->assets->errors()];
        }

        $this->activity->log('fixed_assets', 'updated', $actingUserId, "Updated fixed asset #{$id}", (string) $id);

        return ['success' => true];
    }

    public function delete(int $id, ?int $actingUserId): array
    {
        $asset = $this->assets->find($id);
        if (! $asset) {
            return ['success' => false, 'error' => 'Fixed asset not found.'];
        }

        if ($this->runLines->countForAsset($id) > 0) {
            return ['success' => false, 'error' => 'Cannot delete an asset that has depreciation history.'];
        }
        if ($this->disposals->countForAsset($id) > 0) {
            return ['success' => false, 'error' => 'Cannot delete an asset that has disposal records.'];
        }

        $this->assets->delete($id);
        $this->activity->log('fixed_assets', 'deleted', $actingUserId, "Deleted fixed asset #{$id}", (string) $id);

        return ['success' => true];
    }

    protected function mapInput(array $input): array
    {
        $account = static function ($key) use ($input): ?int {
            $id = (int) ($input[$key] ?? 0);

            return $id > 0 ? $id : null;
        };

        return [
            'name'                    => trim((string) $input['name']),
            'category_id'             => (int) $input['category_id'],
            'purchase_date'           => $input['purchase_date'] ?? date('Y-m-d'),
            'in_service_date'         => ! empty($input['in_service_date']) ? $input['in_service_date'] : null,
            'location'                => ! empty($input['location']) ? trim((string) $input['location']) : null,
            'asset_account_id'        => $account('asset_account_id'),
            'accum_depr_account_id'   => $account('accum_depr_account_id'),
            'depr_expense_account_id' => $account('depr_expense_account_id'),
            'notes'                   => ! empty($input['notes']) ? trim((string) $input['notes']) : null,
        ];
    }
}
