<?php

namespace App\Services\Billing;

use App\Models\PaymentModel;
use App\Models\RefundRequestModel;
use App\Services\Support\ActivityLogger;
use App\Services\Support\AuditService;

class RefundService
{
    private RefundRequestModel $refunds;
    private PaymentModel $payments;
    private PaymentService $paymentService;
    private ActivityLogger $activity;
    private AuditService $audit;

    public function __construct()
    {
        $this->refunds        = new RefundRequestModel();
        $this->payments       = new PaymentModel();
        $this->paymentService = new PaymentService();
        $this->activity       = new ActivityLogger();
        $this->audit          = new AuditService();
    }

    public function requestRefund(int $paymentId, int $requestedByUserId, string $reason): int
    {
        $payment = $this->payments->find($paymentId);
        if (! $payment || $payment['status'] !== 'success') {
            throw new \InvalidArgumentException('Only successful payments can be refunded.');
        }

        $id = $this->refunds->insert([
            'payment_id'            => $paymentId,
            'requested_by_user_id'  => $requestedByUserId,
            'reason'                => $reason,
            'status'                => 'pending',
            'created_at'            => date('Y-m-d H:i:s'),
        ], true);

        $this->activity->log($requestedByUserId, (int) $payment['agency_id'], null, 'refund_requested', ['payment_id' => $paymentId]);

        return $id;
    }

    public function approve(int $refundRequestId, int $processedByUserId): array
    {
        $request = $this->refunds->find($refundRequestId);
        if (! $request || $request['status'] !== 'pending') {
            throw new \RuntimeException('Refund request not found or already processed.');
        }

        $payment = $this->payments->find($request['payment_id']);
        $gateway = $this->paymentService->gatewayFor($payment['gateway']);

        $result = $gateway->refund($payment['gateway_transaction_id'], (float) $payment['amount']);

        $newStatus = in_array($result['status'], ['succeeded', 'manual_processing_required'], true) ? 'processed' : 'approved';

        $this->refunds->update($refundRequestId, [
            'status'        => $newStatus,
            'processed_by'  => $processedByUserId,
            'processed_at'  => date('Y-m-d H:i:s'),
        ]);

        $this->payments->update($payment['id'], ['status' => 'refunded']);

        $this->audit->record($processedByUserId, 'billing', 'refund_approved', $refundRequestId, null, $result);

        return ['refund_status' => $newStatus, 'gateway_result' => $result];
    }

    public function reject(int $refundRequestId, int $processedByUserId): void
    {
        $request = $this->refunds->find($refundRequestId);
        if (! $request || $request['status'] !== 'pending') {
            throw new \RuntimeException('Refund request not found or already processed.');
        }

        $this->refunds->update($refundRequestId, [
            'status'       => 'rejected',
            'processed_by' => $processedByUserId,
            'processed_at' => date('Y-m-d H:i:s'),
        ]);

        $this->audit->record($processedByUserId, 'billing', 'refund_rejected', $refundRequestId, null, null);
    }

    public function pendingQueue(): array
    {
        return $this->refunds->pending();
    }
}
