<?php
namespace Incoviba\Controller\API;

use Throwable;
use Psr\Http\Message\ResponseInterface;

trait withJson
{
    public function withJson(ResponseInterface $response, array|object $data = [], int $statusCode = 200): ResponseInterface
    {
        $response->getBody()->write(json_encode($data));
        return $response->withStatus($statusCode)->withHeader('Content-Type', 'application/json');
    }
    public function parseError(Throwable $exception): array
    {
        return [
            'code' => $exception->getCode(),
            'message' => $exception->getMessage(),
            'file' => $this->parseFilename($exception->getFile()),
            'line' => $exception->getLine(),
            'trace' => $this->parseStack($exception->getTraceAsString()),
            'previous' => ($exception->getPrevious() instanceof Throwable) ? $this->parseError($exception->getPrevious()) : ''
        ];
    }
    public function withError(ResponseInterface $response, Throwable $exception): ResponseInterface
    {
        $output = $this->parseError($exception);

        $response->getBody()->write(json_encode(['error' => $output]));
        return $response->withHeader('Content-Type', 'application/json');
    }
    public function withErrors(ResponseInterface $response, array $errors): ResponseInterface
    {
        foreach ($errors as $error) {
            $response = $this->withError($response, $error);
        }

        return $response;
    }

    protected function parseFilename(string $filename): string
    {
        return str_replace('/code/', '', $filename);
    }
    protected function parseStack(string|array $stack): array
    {
        if (is_string($stack)) {
            $stack = explode(PHP_EOL, $stack);
        }
        $output = [];
        foreach ($stack as $line) {
            $index = substr($line, 1, strpos($line, ' ') - 1);
            $content = substr($line, strpos($line, ' ') + 1);
            if (str_contains($line, '{main}')) {
                $output [] = [
                    'stack' => $index,
                    'message' => $content
                ];
                continue;
            }
            if (str_starts_with($content, '[internal function]')) {
                $content = substr($content, strlen('[internal function]: '));
                $output [] = [
                    'stack' => $index,
                    'type' => 'internal function',
                    'message' => $content
                ];
                continue;
            }
            $fileData = substr($content, 0, strpos($content, ' '));
            $file = substr($fileData, 0, strrpos($fileData, '('));
            $fileLine = (int) substr($fileData, strrpos($fileData, '(') + 1, -2);
            $error = substr($content, strlen($fileData) + 1);
            $output []= [
                'stack' => $index,
                'file' => $this->parseFilename($file),
                'line' => $fileLine,
                'error' => $error
            ];
        }
        return $output;
    }
}
