<?php

declare(strict_types=1);

namespace Drupal\flowdrop\Controller\Api;

use Drupal\Core\Cache\CacheableJsonResponse;
use Drupal\Core\Cache\CacheableMetadata;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

/**
 * Standardized API response helpers for FlowDrop controllers.
 *
 * Provides a consistent response envelope across all API endpoints:
 * - Success: { "success": true, "data": ... }
 * - Error: { "success": false, "error": "..." }
 * - Paginated: { "success": true, "data": [...], "pagination": { ... } }
 *
 * @internal This trait is not part of the public API and may change without notice.
 */
trait ApiResponseTrait {

  /**
   * Returns a standardized success response.
   *
   * @param mixed $data
   *   The response data.
   * @param int $status
   *   The HTTP status code.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   The JSON response.
   */
  protected function successResponse(mixed $data, int $status = Response::HTTP_OK): JsonResponse {
    return new JsonResponse([
      'success' => TRUE,
      'data' => $data,
    ], $status);
  }

  /**
   * Returns a standardized error response.
   *
   * @param string $error
   *   The error message.
   * @param int $status
   *   The HTTP status code.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   The JSON response.
   */
  protected function errorResponse(string $error, int $status = Response::HTTP_INTERNAL_SERVER_ERROR): JsonResponse {
    return new JsonResponse([
      'success' => FALSE,
      'error' => $error,
    ], $status);
  }

  /**
   * Returns a standardized paginated response.
   *
   * @param array $data
   *   The paginated data.
   * @param int $total
   *   Total count of items.
   * @param int $limit
   *   Items per page.
   * @param int $offset
   *   Current offset.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   The JSON response.
   */
  protected function paginatedResponse(array $data, int $total, int $limit, int $offset): JsonResponse {
    return new JsonResponse([
      'success' => TRUE,
      'data' => $data,
      'pagination' => [
        'total' => $total,
        'limit' => $limit,
        'offset' => $offset,
        'has_more' => ($offset + $limit) < $total,
      ],
    ]);
  }

  /**
   * Returns a cacheable standardized success response.
   *
   * @param mixed $data
   *   The response data.
   * @param \Drupal\Core\Cache\CacheableMetadata $cacheMetadata
   *   Cache metadata.
   *
   * @return \Drupal\Core\Cache\CacheableJsonResponse
   *   The cacheable JSON response.
   */
  protected function cacheableSuccessResponse(mixed $data, CacheableMetadata $cacheMetadata): CacheableJsonResponse {
    $response = new CacheableJsonResponse([
      'success' => TRUE,
      'data' => $data,
    ]);
    $response->addCacheableDependency($cacheMetadata);
    return $response;
  }

  /**
   * Returns a cacheable standardized error response.
   *
   * @param string $error
   *   The error message.
   * @param int $status
   *   The HTTP status code.
   * @param \Drupal\Core\Cache\CacheableMetadata $cacheMetadata
   *   Cache metadata.
   *
   * @return \Drupal\Core\Cache\CacheableJsonResponse
   *   The cacheable JSON response.
   */
  protected function cacheableErrorResponse(string $error, int $status, CacheableMetadata $cacheMetadata): CacheableJsonResponse {
    $response = new CacheableJsonResponse([
      'success' => FALSE,
      'error' => $error,
    ], $status);
    $response->addCacheableDependency($cacheMetadata);
    return $response;
  }

  /**
   * Decodes and validates a JSON request body.
   *
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The HTTP request.
   *
   * @return array
   *   The decoded JSON data.
   *
   * @throws \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
   *   When the request body contains invalid JSON.
   */
  protected function decodeJsonRequest(Request $request): array {
    $content = $request->getContent();

    if (empty($content)) {
      throw new BadRequestHttpException('Request body is empty');
    }

    $data = json_decode($content, TRUE);

    if (json_last_error() !== JSON_ERROR_NONE) {
      throw new BadRequestHttpException('Request body contains invalid JSON');
    }

    if (!is_array($data)) {
      throw new BadRequestHttpException('Request body must be a JSON object');
    }

    return $data;
  }

}
