<?php

declare(strict_types=1);

namespace Drupal\conductor\Controller;

use Drupal\conductor\Exception\UnableToAssignDraftToEntityException;
use Drupal\conductor\Repository\DraftRepository;
use Drupal\conductor\Repository\DraftRepositoryInterface;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * Controller for handle the draft API calls.
 */
final readonly class ConductorDraftApiController implements ContainerInjectionInterface {

  public function __construct(
    private DraftRepositoryInterface $draftRepository,
  ) {}

  public static function create(ContainerInterface $container): self {
    return new self(
      $container->get(DraftRepository::class)
    );
  }

  public function __invoke(Request $request, string $entity_type, int $entity_id): JsonResponse {
    return match($request->getMethod()) {
      'PUT' => $this->updateDraft($request, $entity_type, $entity_id),
      'POST' => $this->createDraft($request, $entity_type, $entity_id),
      'DELETE' => $this->deleteDraft($request, $entity_type, $entity_id),
      'GET' => $this->getDraft($request, $entity_type, $entity_id),
      default => new JsonResponse(['error' => 'Method not allowed'], Response::HTTP_METHOD_NOT_ALLOWED),
    };
  }

  /**
   * Method to get the draft from the canvas page.
   */
  private function getDraft(Request $request, string $entity_type, int $entity_id): JsonResponse {
    try {
      $draft = $this->draftRepository->getDraft($entity_type, $entity_id);
      if (empty($draft)) {
        return new JsonResponse(['error' => 'Draft not found'], Response::HTTP_NOT_FOUND);
      }

      return new JsonResponse($draft);
    }
    catch (\Exception $e) {
      return $this->handleError("Error fetching the draft for entity $entity_type $entity_id", $e);
    }
  }

  /**
   * Method to link a draft with an entity.
   */
  public function createDraft(Request $request, string $entity_type, int $entity_id): JsonResponse {
    try {
      $json = json_decode($request->getContent(), TRUE, flags: JSON_THROW_ON_ERROR);
      $requested_draft_id = $json['draftId'] ?? '';
      \assert(is_string($requested_draft_id) && $requested_draft_id !== '');

      // Idempotent create: if the same mapping already exists, return 200 OK.
      $existing = $this->draftRepository->getDraft($entity_type, $entity_id);
      if (!empty($existing) && isset($existing['draft_id']) && $existing['draft_id'] === $requested_draft_id) {
        return $this->handleSuccessfulResponse("success", Response::HTTP_OK);
      }

      $this->draftRepository->createDraft($entity_type, $entity_id, $requested_draft_id);
      return $this->handleSuccessfulResponse("success", Response::HTTP_CREATED);
    }
    catch (UnableToAssignDraftToEntityException $e) {
      return $this->handleError("Unable to link draftId to entity $entity_type $entity_id", $e, Response::HTTP_UNPROCESSABLE_ENTITY);
    }
    catch (\Exception $e) {
      return $this->handleError("Error creating the draft for entity $entity_type $entity_id", $e);
    }
  }

  /**
   * Method to update a draft from a canvas page.
   */
  private function updateDraft(Request $request, string $entity_type, int $entity_id): JsonResponse {
    try {
      $json = json_decode($request->getContent(), TRUE, flags: JSON_THROW_ON_ERROR);
      $this->draftRepository->updateDraft($entity_type, $entity_id, $json['draftId']);
      return $this->handleSuccessfulResponse("Draft updated for entity $entity_type $entity_id");
    }
    catch (\Exception $e) {
      return $this->handleError("Error updating the draft for entity $entity_type $entity_id", $e);
    }
  }

  /**
   * Method to delete the link between a draft and an entity.
   */
  private function deleteDraft(Request $request, string $entity_type, int $entity_id): JsonResponse {
    try {
      if ($this->draftRepository->deleteDraft($entity_type, $entity_id)) {
        return $this->handleSuccessfulResponse("Draft deleted for entity $entity_type $entity_id");
      }
      else {
        return new JsonResponse(['error' => "Draft for canvas page $entity_id not found"], Response::HTTP_NOT_FOUND);
      }
    }
    catch (\Exception $e) {
      return $this->handleError("Error deleting the draft for entity $entity_type $entity_id", $e);
    }
  }

  private function handleSuccessfulResponse(string $message, int $status_code = 200): JsonResponse {
    return new JsonResponse([
      'message' => $message,
    ], $status_code);
  }

  private function handleError(string $message, \Exception $e, int $status_code = 500): JsonResponse {
    $error = [
      'error' => $message,
      'exception' => $e->getMessage(),
    ];
    return new JsonResponse($error, $status_code);
  }

}
