<?php

namespace App\Services\Billing;

use App\Enums\InvoiceStatus;
use App\Enums\PaymentStatus;
use App\Models\Business;
use App\Models\Invoice;
use App\Models\Payment;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class PaymentRecordService
{
    public function __construct(private readonly InvoiceService $invoiceService)
    {
    }

    public static function methods(): array
    {
        return [
            'cash' => 'Cash',
            'card' => 'Card',
            'bank_transfer' => 'Bank Transfer',
            'stripe' => 'Stripe',
            'paypal' => 'PayPal',
            'wallet' => 'Digital Wallet',
            'other' => 'Other',
        ];
    }

    public function record(Business $business, Invoice $invoice, array $data): Payment
    {
        return DB::transaction(function () use ($business, $invoice, $data): Payment {
            $invoice = Invoice::query()
                ->forBusiness($business)
                ->whereKey($invoice->id)
                ->lockForUpdate()
                ->firstOrFail();

            if ($invoice->status_value === InvoiceStatus::Cancelled->value) {
                throw ValidationException::withMessages([
                    'amount' => 'Cancelled invoices cannot receive payments.',
                ]);
            }

            $amount = round((float) $data['amount'], 2);

            if (($data['status'] ?? PaymentStatus::Paid->value) === PaymentStatus::Paid->value
                && $invoice->balance_due > 0
                && $amount > ((float) $invoice->balance_due + 0.01)) {
                throw ValidationException::withMessages([
                    'amount' => 'Payment amount cannot exceed the invoice balance.',
                ]);
            }

            $payment = Payment::query()->create([
                'business_id' => $business->id,
                'invoice_id' => $invoice->id,
                'customer_id' => $invoice->customer_id,
                'amount' => $amount,
                'currency' => $invoice->currency,
                'method' => $data['method'],
                'status' => $data['status'] ?? PaymentStatus::Paid->value,
                'transaction_id' => $data['transaction_id'] ?? null,
                'paid_at' => $data['paid_at'] ?? now(),
                'note' => $data['note'] ?? null,
            ]);

            $this->invoiceService->refreshTotalsAndStatus($invoice);

            if ($payment->status_value === PaymentStatus::Paid->value && $payment->customer_id) {
                $payment->customer()->increment('total_spent', $amount);
            }

            return $payment->refresh();
        });
    }
}
