<?php

namespace Drupal\nodehive_mcp\Plugin\Mcp;

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\mcp\Attribute\Mcp;
use Drupal\mcp\Plugin\McpPluginBase;
use Drupal\mcp\ServerFeatures\Tool;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * MCP plugin for updating nodes in NodeHive Spaces.
 */
#[Mcp(
  id: 'update-node-tool',
  name: new TranslatableMarkup('Update Node Tool'),
  description: new TranslatableMarkup('Provides MCP tool for updating existing nodes in NodeHive Spaces.'),
)]
class UpdateNodeTool extends McpPluginBase implements ContainerFactoryPluginInterface {

  use StringTranslationTrait;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The module handler.
   *
   * @var \Drupal\Core\Extension\ModuleHandlerInterface
   */
  protected $moduleHandler;

  /**
   * {@inheritDoc}
   */
  public static function create(
    ContainerInterface $container,
    array $configuration,
    $plugin_id,
    $plugin_definition,
  ) {
    $instance = parent::create(
      $container, $configuration, $plugin_id, $plugin_definition
    );
    $instance->entityTypeManager = $container->get('entity_type.manager');
    $instance->moduleHandler = $container->get('module_handler');

    return $instance;
  }

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration(): array {
    return [
      'enabled' => TRUE,
      'config' => [],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(
    array $form,
    FormStateInterface $form_state,
  ): array {
    // No specific configuration needed for this tool.
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function getTools(): array {
    return [
      new Tool(
        name: 'update-node-in-space',
        description: 'Update an existing node/content item in a NodeHive Space.',
        inputSchema: [
          'type' => 'object',
          'properties' => [
            'node_id' => [
              'type' => 'integer',
              'description' => 'The ID of the node to update.',
            ],
            'title' => [
              'type' => 'string',
              'description' => 'The new title of the node (optional).',
            ],
            'body' => [
              'type' => 'string',
              'description' => 'The new body/content of the node (optional).',
            ],
            'status' => [
              'type' => 'boolean',
              'description' => 'Whether the node should be published (optional).',
            ],
            'space_id' => [
              'type' => 'integer',
              'description' => 'Move the node to a different space (optional).',
            ],
            'author_id' => [
              'type' => 'integer',
              'description' => 'Change the author of the node (optional).',
            ],
            'fields' => [
              'type' => 'object',
              'description' => 'Additional field values to update (optional).',
              'additionalProperties' => TRUE,
            ],
          ],
          'required' => ['node_id'],
        ],
      ),
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function executeTool(string $toolId, mixed $arguments): array {
    if ($toolId === md5('update-node-in-space')) {
      return $this->executeUpdateNodeInSpace($arguments);
    }

    throw new \InvalidArgumentException('Unknown tool: ' . $toolId);
  }

  /**
   * Execute the update node in space tool.
   */
  protected function executeUpdateNodeInSpace(array $arguments): array {
    try {
      // Validate required fields.
      if (empty($arguments['node_id'])) {
        throw new \InvalidArgumentException('Node ID is required.');
      }

      // Load the node.
      $node_storage = $this->entityTypeManager->getStorage('node');
      $node = $node_storage->load($arguments['node_id']);

      if (!$node) {
        throw new \InvalidArgumentException('Node with ID ' . $arguments['node_id'] . ' not found.');
      }

      // Note: Removing explicit access check to match CreateNodeTool behavior
      // The access control is handled at the MCP plugin level via hasAccess()
      $updated_fields = [];

      // Update title if provided.
      if (isset($arguments['title']) && !empty($arguments['title'])) {
        $node->setTitle($arguments['title']);
        $updated_fields[] = 'title';
      }

      // Update body if provided and the node has a body field.
      if (isset($arguments['body']) && $node->hasField('body')) {
        $node->set('body', [
          'value' => $arguments['body'],
          'format' => 'basic_html',
        ]);
        $updated_fields[] = 'body';
      }

      // Update status if provided.
      if (isset($arguments['status'])) {
        $node->setPublished($arguments['status']);
        $updated_fields[] = 'status';
      }

      // Update author if provided.
      if (isset($arguments['author_id'])) {
        $user_storage = $this->entityTypeManager->getStorage('user');
        $author = $user_storage->load($arguments['author_id']);
        if (!$author) {
          throw new \InvalidArgumentException('Author with ID ' . $arguments['author_id'] . ' does not exist.');
        }
        $node->setOwnerId($arguments['author_id']);
        $updated_fields[] = 'author';
      }

      // Update space if provided.
      if (isset($arguments['space_id'])) {
        $space_storage = $this->entityTypeManager->getStorage('nodehive_space');
        $space = $space_storage->load($arguments['space_id']);
        if (!$space) {
          throw new \InvalidArgumentException('Space with ID ' . $arguments['space_id'] . ' not found.');
        }

        // Check if the content type is allowed in the new space.
        $allowed_content_types = [];
        if (!$space->get('content_types')->isEmpty()) {
          foreach ($space->get('content_types')->referencedEntities() as $content_type) {
            $allowed_content_types[] = $content_type->id();
          }

          if (!empty($allowed_content_types) && !in_array($node->bundle(), $allowed_content_types)) {
            throw new \InvalidArgumentException(
              sprintf(
                'Content type "%s" is not allowed in space "%s". Allowed types: %s',
                $node->bundle(),
                $space->label(),
                implode(', ', $allowed_content_types)
              )
            );
          }
        }

        if ($node->hasField('nodehive_space')) {
          $node->set('nodehive_space', [$arguments['space_id']]);
          $updated_fields[] = 'space';
        }
      }

      // Update additional fields if provided.
      if (isset($arguments['fields']) && is_array($arguments['fields'])) {
        foreach ($arguments['fields'] as $field_name => $field_value) {
          if ($node->hasField($field_name)) {
            $node->set($field_name, $field_value);
            $updated_fields[] = $field_name;
          }
        }
      }

      // Save the node if any changes were made.
      if (!empty($updated_fields)) {
        $node->save();
      }

      // Get current space information.
      $current_space = NULL;
      if ($node->hasField('nodehive_space') && !$node->get('nodehive_space')->isEmpty()) {
        $space_entity = $node->get('nodehive_space')->entity;
        if ($space_entity) {
          $current_space = [
            'id' => $space_entity->id(),
            'label' => $space_entity->label(),
          ];
        }
      }

      $result = [
        'success' => TRUE,
        'message' => 'Node updated successfully.',
        'node' => [
          'id' => $node->id(),
          'title' => $node->getTitle(),
          'type' => $node->bundle(),
          'status' => $node->isPublished() ? 'Published' : 'Unpublished',
          'author' => [
            'id' => $node->getOwnerId(),
            'name' => $node->getOwner()->getDisplayName(),
          ],
          'created' => date('Y-m-d H:i:s', $node->getCreatedTime()),
          'changed' => date('Y-m-d H:i:s', $node->getChangedTime()),
          'url' => $node->toUrl()->toString(),
          'space' => $current_space,
        ],
        'updated_fields' => $updated_fields,
      ];

      return [
        [
          'type' => 'text',
          'text' => $this->formatUpdateResult($result),
        ],
      ];

    }
    catch (\Exception $e) {
      return [
        [
          'type' => 'text',
          'text' => 'Error updating node: ' . $e->getMessage(),
        ],
      ];
    }
  }

  /**
   * Format the update result for display.
   */
  protected function formatUpdateResult(array $result): string {
    $output = "=== NODE UPDATE RESULT ===\n\n";
    $output .= "✓ " . $result['message'] . "\n\n";

    $node = $result['node'];
    $output .= "=== UPDATED NODE DETAILS ===\n";
    $output .= "ID: " . $node['id'] . "\n";
    $output .= "Title: " . $node['title'] . "\n";
    $output .= "Type: " . $node['type'] . "\n";
    $output .= "Status: " . $node['status'] . "\n";
    $output .= "Author: " . $node['author']['name'] . " (ID: " . $node['author']['id'] . ")\n";
    $output .= "Created: " . $node['created'] . "\n";
    $output .= "Last Modified: " . $node['changed'] . "\n";
    $output .= "URL: " . $node['url'] . "\n";

    if ($node['space']) {
      $output .= "Space: " . $node['space']['label'] . " (ID: " . $node['space']['id'] . ")\n";
    }
    else {
      $output .= "Space: Not assigned to any space\n";
    }

    if (!empty($result['updated_fields'])) {
      $output .= "\n=== FIELDS UPDATED ===\n";
      foreach ($result['updated_fields'] as $field) {
        $output .= "• " . ucfirst($field) . "\n";
      }
    }
    else {
      $output .= "\n=== NO CHANGES MADE ===\n";
      $output .= "No field values were provided for update.\n";
    }

    return $output;
  }

  /**
   * {@inheritdoc}
   */
  public function hasAccess(): AccessResult {
    return AccessResult::allowedIfHasPermission(
      $this->currentUser, 'use nodehive mcp tools'
    );
  }

  /**
   * {@inheritdoc}
   */
  public function checkRequirements(): bool {
    return $this->moduleHandler->moduleExists('nodehive_core') &&
           $this->moduleHandler->moduleExists('mcp');
  }

}
