<?php

namespace App\Modules\HR\Loans\Services;

use App\Modules\HR\Loans\DTOs\LoanData;
use App\Modules\HR\Loans\Events\LoanApproved;
use App\Modules\HR\Loans\Models\Loan;
use App\Modules\HR\Loans\Repositories\LoanRepository;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class LoanService
{
    public function __construct(private readonly LoanRepository $repository) {}

    public function create(LoanData $dto, int $tenantId, int $userId): Loan
    {
        return DB::transaction(function () use ($dto, $tenantId, $userId): Loan {
            $data = $dto->attributes;
            $total = (float) $data['amount'] * (1 + ((float) ($data['interest_rate'] ?? 0) / 100));
            $installment = round($total / (int) $data['installment_count'], 2);
            $loan = $this->repository->create(array_merge($data, [
                'tenant_id' => $tenantId, 'created_by' => $userId, 'status' => 'draft',
                'installment_amount' => $installment, 'remaining_balance' => $total,
            ]));
            $date = Carbon::parse($data['start_date']);
            for ($i = 0; $i < (int) $data['installment_count']; $i++) {
                $amount = $i === (int) $data['installment_count'] - 1
                    ? round($total - ($installment * $i), 2) : $installment;
                $loan->installments()->create(['due_date' => $date->copy()->addMonths($i), 'amount' => $amount]);
            }

            return $loan->load('installments');
        });
    }

    public function transition(Loan $loan, string $action, int $userId): Loan
    {
        $map = [
            'submit' => ['draft' => 'submitted'], 'approve' => ['submitted' => 'approved'],
            'reject' => ['submitted' => 'rejected'], 'cancel' => ['draft' => 'cancelled', 'submitted' => 'cancelled'],
            'settle' => ['approved' => 'settled', 'active' => 'settled', 'partially_paid' => 'settled'],
        ];
        $next = $map[$action][$loan->status] ?? null;
        if ($next === null) {
            throw ValidationException::withMessages(['status' => __('loans.invalid_transition')]);
        }
        $data = ['status' => $next];
        if ($action === 'approve') {
            $data += ['approved_by' => $userId, 'approved_at' => now()];
        }
        if ($action === 'settle') {
            $data['remaining_balance'] = 0;
            $loan->installments()->where('status', 'pending')->update(['status' => 'paid', 'paid_amount' => DB::raw('amount')]);
        }

        $updated = $this->repository->update($loan, $data);
        if ($action === 'approve') {
            LoanApproved::dispatch($updated);
        }

        return $updated;
    }
}
