<?php

namespace Solspace\Freeform\controllers;

use Solspace\Freeform\Library\Exceptions\Api\ApiException;
use Symfony\Component\Serializer\Serializer;
use yii\web\NotFoundHttpException;
use yii\web\Response;

abstract class BaseApiController extends BaseController
{
    public function runAction($id, $params = [])
    {
        try {
            return parent::runAction($id, $params); // TODO: Change the autogenerated stub
        } catch (ApiException $exception) {
            $this->response->statusCode = $exception->getCode();

            return $this->asJson(['errors' => $exception->getErrors()->asArray()]);
        }
    }

    public function actionIndex($id = null): Response
    {
        $request = $this->request;

        try {
            $content = match ($request->method) {
                'GET' => null !== $id ? $this->getOne($id) : $this->get(),
                'POST' => $this->post($id),
                'PUT' => $this->put($id),
                'DELETE' => $this->delete($id),
                default => throw new NotFoundHttpException('Method not supported'),
            };
        } catch (ApiException $exception) {
            $this->response->statusCode = $exception->getCode();

            return $this->asJson(['errors' => $exception->getErrors()->asArray()]);
        }

        if (null === $content) {
            return $this->asEmptyResponse();
        }

        return $this->asSerializedJson($content);
    }

    protected function get(): array|object
    {
        throw new NotFoundHttpException('GET request not supported');
    }

    protected function getOne(int|string $id): array|object|null
    {
        throw new NotFoundHttpException('GET request not supported');
    }

    protected function post(int|string|null $id = null): array|object|null
    {
        throw new NotFoundHttpException('POST request not supported');
    }

    protected function put(int|string|null $id = null): array|object|null
    {
        throw new NotFoundHttpException('PUT request not supported');
    }

    protected function delete(int $id): ?bool
    {
        throw new NotFoundHttpException('DELETE request not supported');
    }

    protected function getSerializer(): Serializer
    {
        return \Craft::$container->get(Serializer::class);
    }

    protected function asEmptyResponse(?int $statusCode = null): Response
    {
        $this->response->format = Response::FORMAT_RAW;
        $this->response->content = '';
        if ($statusCode) {
            $this->response->statusCode = $statusCode;
        }

        return $this->response;
    }

    protected function asSerializedJson(mixed $content, ?int $statusCode = null, ?array $context = null): Response
    {
        $context ??= ['preserve_empty_objects' => true];
        $serialized = $this->getSerializer()->serialize($content, 'json', $context);

        $this->response->format = Response::FORMAT_JSON;
        $this->response->content = $serialized;
        if ($statusCode) {
            $this->response->statusCode = $statusCode;
        }

        return $this->response;
    }

    protected function asFile(mixed $path, string $filename, array $options = []): Response
    {
        return $this->response->sendFile($path, $filename, $options);
    }
}
