<?php

namespace App\Http\Controllers;

use App\Models\Customer;
use App\Models\PaymentOrder;
use App\Services\PaymentService;
use App\Services\SignatureService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

/**
 * Payment endpoints.
 *
 * POST /api/payments/create           — Create a payment order with AIK Digital
 * POST /api/callbacks/payment         — Receive AIK Digital payment callback (notifyUrl)
 * GET  /api/payments/{orderId}/status — Query a payment order status
 */
class PaymentController extends Controller
{
    public function __construct(
        private PaymentService   $paymentService,
        private SignatureService  $signatureService,
    ) {}

    // ─────────────────────────────────────────────────────────────────────────
    // CREATE PAYMENT
    // ─────────────────────────────────────────────────────────────────────────

    /**
     * POST /api/payments/create
     *
     * Body:
     * {
     *   "open_id":      "uuid-v4",
     *   "policy_title": "Health Basic Plan",
     *   "amount":       5000,           // PKR whole rupees
     *   "product_code": "HEALTH-BASIC"  // optional
     * }
     */
    public function create(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'open_id'      => 'required|string',
            'policy_title' => 'required|string|max:255',
            'amount'       => 'required|integer|min:1',
            'product_code' => 'nullable|string|max:100',
        ]);

        $customer = Customer::where('open_id', $validated['open_id'])->first();

        if (!$customer) {
            return response()->json([
                'success' => false,
                'message' => 'Customer not found. Complete onboarding via the iframe first.',
            ], 404);
        }

        try {
            $order = $this->paymentService->createPaymentOrder(
                customer:    $customer,
                policyTitle: $validated['policy_title'],
                amountPkr:   (int) $validated['amount'],
                productCode: $validated['product_code'] ?? null,
            );

            return response()->json([
                'success'            => true,
                'payment_order_id'   => $order->payment_order_id,
                'aik_transaction_id' => $order->aik_transaction_id,
                'aik_result_status'  => $order->aik_result_status,
                'aik_order_status'   => $order->aik_order_status,
                'local_status'       => $order->status,
                'message'            => $this->statusMessage($order->aik_result_status),
            ], 201);

        } catch (\Throwable $e) {
            Log::error('PaymentController@create: ' . $e->getMessage());
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

    // ─────────────────────────────────────────────────────────────────────────
    // PAYMENT CALLBACK (notifyUrl)
    // ─────────────────────────────────────────────────────────────────────────

    /**
     * POST /api/callbacks/payment
     *
     * AIK Digital posts the payment result here (asynchronously).
     * This is the paymentNotifyUrl registered in createPayment.
     *
     * Per spec (Section 6.7): ALWAYS return HTTP 200 after signature verification
     * to prevent AIK Digital retry storms. Decouple internal logic from the ack.
     */
    public function callback(Request $request): JsonResponse
    {
        $signatureHeader = $request->header('Signature', '');
        $body            = $request->getContent();

        // ── Step 1: Verify AIK Digital's RSA signature ────────────────────
        if (!empty($signatureHeader)) {
            $isValid = $this->signatureService->verifyCallback($body, $signatureHeader);
            if (!$isValid) {
                Log::error('PaymentController@callback: INVALID SIGNATURE — rejecting payload');
                return response()->json(['result' => ['resultCode' => 'INVALID_SIGNATURE']], 400);
            }
        } else {
            // In sandbox/testing, AIK Digital may not always send a signature.
            // Log and proceed — tighten this to a rejection in production.
            Log::warning('PaymentController@callback: no Signature header present (sandbox mode?)');
        }

        $payload = $request->json()->all();

        Log::info('PaymentController@callback: received', [
            'txnId'  => $payload['paymentTransactionID'] ?? null,
            'status' => $payload['resultStatus']         ?? null,
        ]);

        try {
            $order = $this->paymentService->processCallback($payload);

            // ── Step 7: Always ACK with HTTP 200 ──────────────────────────
            return response()->json(['result' => ['resultCode' => 'SUCCESS']]);

        } catch (\InvalidArgumentException $e) {
            Log::error('PaymentController@callback: validation error — ' . $e->getMessage());
            // Still return 200 to avoid retries; internal alert handles this
            return response()->json(['result' => ['resultCode' => 'SUCCESS']]);

        } catch (\Throwable $e) {
            Log::error('PaymentController@callback: unexpected error — ' . $e->getMessage());
            return response()->json(['result' => ['resultCode' => 'SUCCESS']]);
        }
    }

    // ─────────────────────────────────────────────────────────────────────────
    // STATUS QUERY
    // ─────────────────────────────────────────────────────────────────────────

    /**
     * GET /api/payments/{orderId}/status
     *
     * Query the local EFUL DB status of a payment order.
     * Use this to poll for orders awaiting callback (U status, timeout scenarios).
     */
    public function status(string $orderId): JsonResponse
    {
        $order = PaymentOrder::where('payment_order_id', $orderId)
            ->with('customer:id,open_id,name,msisdn')
            ->first();

        if (!$order) {
            return response()->json(['success' => false, 'message' => 'Order not found.'], 404);
        }

        return response()->json([
            'success'              => true,
            'payment_order_id'     => $order->payment_order_id,
            'aik_transaction_id'   => $order->aik_transaction_id,
            'local_status'         => $order->status,
            'aik_result_status'    => $order->aik_result_status,
            'aik_result_code'      => $order->aik_result_code,
            'amount'               => $order->amount,
            'policy_title'         => $order->policy_title,
            'callback_received_at' => $order->callback_received_at,
            'policy_activated_at'  => $order->policy_activated_at,
            'customer'             => $order->customer,
        ]);
    }

    // ─────────────────────────────────────────────────────────────────────────

    private function statusMessage(string $status): string
    {
        return match($status) {
            'S' => 'Payment evaluation succeeded. Awaiting callback to activate policy.',
            'A' => 'Payment accepted and in-progress. Awaiting callback.',
            'F' => 'Payment failed. Do not activate policy.',
            'U' => 'Payment outcome unknown. Awaiting callback — do not activate or refund.',
            default => 'Unknown status.',
        };
    }
}
