<?php

declare(strict_types=1);

namespace Drupal\flowdrop_chat\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Flood\FloodInterface;
use Drupal\flowdrop\Controller\Api\ApiResponseTrait;
use Drupal\flowdrop_chat\Service\ChatServiceInterface;
use Drupal\flowdrop_workflow\FlowDropWorkflowInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * API Controller for FlowDrop Chat operations.
 *
 * Provides RESTful endpoints for AI-assisted workflow building chat.
 *
 * @internal This class is not part of the public API and may change without notice.
 */
final class ChatApiController extends ControllerBase {

  use ApiResponseTrait;

  /**
   * The chat service.
   *
   * @var \Drupal\flowdrop_chat\Service\ChatServiceInterface
   */
  protected ChatServiceInterface $chatService;

  /**
   * The flood control service.
   *
   * @var \Drupal\Core\Flood\FloodInterface
   */
  protected FloodInterface $flood;

  /**
   * Maximum chat messages per user per minute.
   */
  private const FLOOD_THRESHOLD = 60;

  /**
   * Flood window in seconds.
   */
  private const FLOOD_WINDOW = 60;

  /**
   * Constructs a ChatApiController object.
   *
   * @param \Drupal\flowdrop_chat\Service\ChatServiceInterface $chat_service
   *   The chat service.
   * @param \Drupal\Core\Flood\FloodInterface $flood
   *   The flood control service.
   */
  public function __construct(
    ChatServiceInterface $chat_service,
    FloodInterface $flood,
  ) {
    $this->chatService = $chat_service;
    $this->flood = $flood;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): static {
    return new static(
      $container->get('flowdrop_chat.chat_service'),
      $container->get('flood'),
    );
  }

  /**
   * Sends a chat message and returns the LLM response.
   *
   * @param string $workflow_id
   *   The workflow ID.
   * @param \Symfony\Component\HttpFoundation\Request $request
   *   The request object.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   JSON response with the LLM response.
   */
  public function sendMessage(string $workflow_id, Request $request): JsonResponse {
    $access = $this->checkWorkflowAccess($workflow_id, 'update');
    if ($access instanceof JsonResponse) {
      return $access;
    }

    $floodId = 'flowdrop_chat.send_message';
    $userId = (string) $this->currentUser()->id();
    if (!$this->flood->isAllowed($floodId, self::FLOOD_THRESHOLD, self::FLOOD_WINDOW, $userId)) {
      return $this->errorResponse('Too many requests. Please wait before sending another message.', Response::HTTP_TOO_MANY_REQUESTS);
    }

    try {
      $data = $this->decodeJsonRequest($request);

      if (!isset($data['message']) || !is_string($data['message']) || trim($data['message']) === '') {
        return $this->errorResponse('Message is required and must be a non-empty string', Response::HTTP_BAD_REQUEST);
      }

      if (strlen($data['message']) > 10000) {
        return $this->errorResponse('Message exceeds maximum allowed length of 10000 characters', Response::HTTP_BAD_REQUEST);
      }

      $message = $data['message'];
      $workflowState = $data['workflowState'] ?? NULL;

      if (is_string($workflowState) && strlen($workflowState) > 500_000) {
        return $this->errorResponse('workflowState exceeds maximum allowed size', Response::HTTP_BAD_REQUEST);
      }

      if (is_array($workflowState)) {
        $nodeCount = count($workflowState['nodes'] ?? []);
        $edgeCount = count($workflowState['edges'] ?? []);
        if ($nodeCount > 500 || $edgeCount > 1000) {
          return $this->errorResponse('workflowState exceeds complexity limits (max 500 nodes, 1000 edges)', Response::HTTP_BAD_REQUEST);
        }
      }

      $this->flood->register($floodId, self::FLOOD_WINDOW, $userId);

      $result = $this->chatService->chat($workflow_id, $message, $workflowState);

      $this->getLogger('flowdrop_chat')->info('Chat message sent for workflow @wid by user @uid.', [
        '@wid' => $workflow_id,
        '@uid' => $userId,
      ]);

      return $this->successResponse($result);

    }
    catch (\Exception $e) {
      $this->getLogger('flowdrop_chat')->error('Error processing chat message: @message', [
        '@message' => $e->getMessage(),
      ]);

      return $this->errorResponse('Failed to process chat message', Response::HTTP_INTERNAL_SERVER_ERROR);
    }
  }

  /**
   * Gets the chat history for a workflow.
   *
   * @param string $workflow_id
   *   The workflow ID.
   *
   * @return \Symfony\Component\HttpFoundation\JsonResponse
   *   JSON response with chat history.
   */
  public function getHistory(string $workflow_id): JsonResponse {
    $access = $this->checkWorkflowAccess($workflow_id, 'view');
    if ($access instanceof JsonResponse) {
      return $access;
    }

    try {
      $history = $this->chatService->getHistory($workflow_id);

      return $this->successResponse($history);

    }
    catch (\Exception $e) {
      $this->getLogger('flowdrop_chat')->error('Error getting chat history: @message', [
        '@message' => $e->getMessage(),
      ]);

      return $this->errorResponse('Failed to get chat history', Response::HTTP_INTERNAL_SERVER_ERROR);
    }
  }

  /**
   * Clears the chat history for a workflow.
   *
   * @param string $workflow_id
   *   The workflow ID.
   *
   * @return \Symfony\Component\HttpFoundation\Response
   *   204 No Content response.
   */
  public function clearHistory(string $workflow_id): Response {
    $access = $this->checkWorkflowAccess($workflow_id, 'update');
    if ($access instanceof JsonResponse) {
      return $access;
    }

    try {
      $this->chatService->clearHistory($workflow_id);

      $this->getLogger('flowdrop_chat')->info('Chat history cleared for workflow @wid by user @uid.', [
        '@wid' => $workflow_id,
        '@uid' => $this->currentUser()->id(),
      ]);

      return new Response('', Response::HTTP_NO_CONTENT);

    }
    catch (\Exception $e) {
      $this->getLogger('flowdrop_chat')->error('Error clearing chat history: @message', [
        '@message' => $e->getMessage(),
      ]);

      return new JsonResponse([
        'success' => FALSE,
        'error' => 'Failed to clear chat history',
      ], Response::HTTP_INTERNAL_SERVER_ERROR);
    }
  }

  /**
   * Loads a workflow entity and checks access.
   *
   * @param string $workflow_id
   *   The workflow entity ID.
   * @param string $operation
   *   The access operation to check ('view', 'update', etc.).
   *
   * @return \Drupal\flowdrop_workflow\FlowDropWorkflowInterface|\Symfony\Component\HttpFoundation\JsonResponse
   *   The workflow entity on success, or a JSON error response on failure.
   */
  protected function checkWorkflowAccess(string $workflow_id, string $operation): FlowDropWorkflowInterface|JsonResponse {
    $workflow = $this->entityTypeManager()
      ->getStorage('flowdrop_workflow')
      ->load($workflow_id);

    if (!$workflow instanceof FlowDropWorkflowInterface) {
      return $this->errorResponse('Workflow not found', Response::HTTP_NOT_FOUND);
    }

    if (!$workflow->access($operation, $this->currentUser())) {
      return $this->errorResponse('Access denied', Response::HTTP_FORBIDDEN);
    }

    return $workflow;
  }

}
