<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api\V1\Payment;

use App\Http\Controllers\Controller;
use App\Models\Payment;
use App\Models\PaymentMethod;
use App\Services\Payment\PaymentRouter;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class PaymentController extends Controller
{
    public function __construct(private readonly PaymentRouter $router)
    {
    }

    public function store(Request $request): JsonResponse
    {
        $data = $request->validate([
            'payment_method_id' => ['required', 'uuid'],
            'order_ref' => ['required', 'string', 'max:120'],
            'amount' => ['required', 'integer', 'min:100'],
            'currency' => ['nullable', 'string', 'max:8'],
            'idempotency_key' => ['nullable', 'string', 'max:191'],
        ]);

        $method = PaymentMethod::findOrFail($data['payment_method_id']);
        abort_unless($method->is_active, Response::HTTP_FORBIDDEN, 'METHOD_INACTIVE');

        $payment = $this->router->authorize($method, $data, auth()->id());

        return response()->json(['data' => $this->present($payment)], Response::HTTP_CREATED);
    }

    public function show(string $id): JsonResponse
    {
        $payment = Payment::findOrFail($id);
        $this->authorizeView($payment);
        return response()->json(['data' => $this->present($payment)]);
    }

    public function refund(Request $request, string $id): JsonResponse
    {
        $payment = Payment::findOrFail($id);
        $this->authorizeRefund($payment);
        $data = $request->validate([
            'amount' => ['required', 'integer', 'min:1'],
            'reason' => ['nullable', 'string', 'max:255'],
        ]);

        try {
            $refund = $this->router->refund($payment, (int) $data['amount'], $data['reason'] ?? null);
        } catch (\DomainException $e) {
            return response()->json(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        return response()->json(['data' => $refund], Response::HTTP_CREATED);
    }

    protected function present(Payment $p): array
    {
        return [
            'id' => $p->id,
            'order_ref' => $p->order_ref,
            'amount' => $p->amount,
            'currency' => $p->currency,
            'status' => $p->status,
            'pg_tid' => $p->pg_tid,
            'paid_at' => $p->paid_at,
            'refunded_at' => $p->refunded_at,
            'payment_method_id' => $p->payment_method_id,
        ];
    }

    protected function authorizeView(Payment $p): void
    {
        $user = auth()->user();
        if ($user && $user->hasAnyRole(['super_admin', 'tenant_admin'])) {
            return;
        }
        abort_unless($user && $p->user_id === $user->id, Response::HTTP_FORBIDDEN);
    }

    protected function authorizeRefund(Payment $p): void
    {
        $user = auth()->user();
        if ($user && $user->hasAnyRole(['super_admin', 'tenant_admin'])) {
            return;
        }
        abort_unless($user && ($p->user_id === $user->id || $user->can('payments.refund')), Response::HTTP_FORBIDDEN);
    }
}
