<?php

namespace PortalPeople\stripe\controllers\api;

use OpenApi\Annotations as OA;
use PortalPeople\stripe\components\StripeClient;
use PortalPeople\stripe\Module;
use RuntimeException;
use Yii;

/**
 * @OA\Tag(
 *   name="Stripe API",
 *   description="Stripe customer, payment intent, refund and balance endpoints"
 * )
 */
class ApiController extends Controller
{
    private ?StripeClient $client = null;
    private ?string $clientInitError = null;

    protected function verbs(): array
    {
        return [
            'customers' => ['GET'],
            'customer' => ['GET'],
            'payment-intent-create' => ['POST'],
            'payment-intent' => ['GET'],
            'refunds' => ['GET'],
            'refund-create' => ['POST'],
            'balance' => ['GET'],
        ];
    }

    public function init(): void
    {
        parent::init();
        /** @var Module $module */
        $module = $this->module;
        try {
            $this->client = StripeClient::fromModule($module);
        } catch (RuntimeException $e) {
            $this->clientInitError = $e->getMessage();
        }
    }

    public function actionCustomers(): array
        /**
         * @OA\Get(
         *   path="/stripe/api/customers",
         *   tags={"Stripe API"},
         *   summary="List Stripe customers",
         *   @OA\Response(response=200, description="Customer list")
         * )
         */
    {
        if ($this->clientInitError !== null) {
            return $this->errorResponse($this->clientInitError, 500);
        }

        try {
            return $this->client->listCustomers(Yii::$app->request->get());
        } catch (RuntimeException $e) {
            return $this->errorResponse($e->getMessage(), 502);
        }
    }

    /**
     * @OA\Get(
     *   path="/stripe/api/customers",
     *   tags={"Stripe API"},
     *   summary="List Stripe customers",
     *   @OA\Response(response=200, description="Customer list")
     * )
     */

    public function actionCustomer(): array
    {
        if ($this->clientInitError !== null) {
            return $this->errorResponse($this->clientInitError, 500);
        }

        $id = trim((string) Yii::$app->request->get('id', ''));
        if ($id === '') {
            return $this->errorResponse('Query parameter "id" is required.', 400);
        }

        try {
            return $this->client->retrieveCustomer($id);
        } catch (RuntimeException $e) {
            return $this->errorResponse($e->getMessage(), 502);
        }
    }

    /**
     * @OA\Get(
     *   path="/stripe/api/customer",
     *   tags={"Stripe API"},
     *   summary="Retrieve a customer by ID",
     *   @OA\Parameter(name="id", in="query", required=true, @OA\Schema(type="string")),
     *   @OA\Response(response=200, description="Customer data")
     * )
     */

    public function actionPaymentIntentCreate(): array
    {
        if ($this->clientInitError !== null) {
            return $this->errorResponse($this->clientInitError, 500);
        }

        $payload = Yii::$app->request->post();
        $idempotencyKey = (string) Yii::$app->request->headers->get('Idempotency-Key', '');

        try {
            return $this->client->createPaymentIntent($payload, $idempotencyKey !== '' ? $idempotencyKey : null);
        } catch (RuntimeException $e) {
            return $this->errorResponse($e->getMessage(), 502);
        }
    }

    /**
     * @OA\Post(
     *   path="/stripe/api/payment-intent-create",
     *   tags={"Stripe API"},
     *   summary="Create a payment intent",
     *   @OA\Response(response=200, description="Payment intent created")
     * )
     */

    public function actionPaymentIntent(): array
    {
        if ($this->clientInitError !== null) {
            return $this->errorResponse($this->clientInitError, 500);
        }

        $id = trim((string) Yii::$app->request->get('id', ''));
        if ($id === '') {
            return $this->errorResponse('Query parameter "id" is required.', 400);
        }

        try {
            return $this->client->retrievePaymentIntent($id);
        } catch (RuntimeException $e) {
            return $this->errorResponse($e->getMessage(), 502);
        }
    }

    /**
     * @OA\Get(
     *   path="/stripe/api/payment-intent",
     *   tags={"Stripe API"},
     *   summary="Retrieve payment intent by ID",
     *   @OA\Parameter(name="id", in="query", required=true, @OA\Schema(type="string")),
     *   @OA\Response(response=200, description="Payment intent data")
     * )
     */

    public function actionRefunds(): array
    {
        if ($this->clientInitError !== null) {
            return $this->errorResponse($this->clientInitError, 500);
        }

        try {
            return $this->client->listRefunds(Yii::$app->request->get());
        } catch (RuntimeException $e) {
            return $this->errorResponse($e->getMessage(), 502);
        }
    }

    /**
     * @OA\Get(
     *   path="/stripe/api/refunds",
     *   tags={"Stripe API"},
     *   summary="List refunds",
     *   @OA\Response(response=200, description="Refund list")
     * )
     */

    public function actionRefundCreate(): array
    {
        if ($this->clientInitError !== null) {
            return $this->errorResponse($this->clientInitError, 500);
        }

        $payload = Yii::$app->request->post();
        $idempotencyKey = (string) Yii::$app->request->headers->get('Idempotency-Key', '');

        try {
            return $this->client->createRefund($payload, $idempotencyKey !== '' ? $idempotencyKey : null);
        } catch (RuntimeException $e) {
            return $this->errorResponse($e->getMessage(), 502);
        }
    }

    /**
     * @OA\Post(
     *   path="/stripe/api/refund-create",
     *   tags={"Stripe API"},
     *   summary="Create a refund",
     *   @OA\Response(response=200, description="Refund created")
     * )
     */

    public function actionBalance(): array
    {
        if ($this->clientInitError !== null) {
            return $this->errorResponse($this->clientInitError, 500);
        }

        try {
            return $this->client->retrieveBalance();
        } catch (RuntimeException $e) {
            return $this->errorResponse($e->getMessage(), 502);
        }
    }

    /**
     * @OA\Get(
     *   path="/stripe/api/balance",
     *   tags={"Stripe API"},
     *   summary="Retrieve Stripe account balance",
     *   @OA\Response(response=200, description="Balance data")
     * )
     */

    private function errorResponse(string $message, int $statusCode): array
    {
        Yii::$app->response->statusCode = $statusCode;
        return ['error' => $message];
    }
}
