<?php

namespace ModernFields\FieldGroups\Locations\Hooks;

use ModernFields\FieldGroups\Repositories\FieldGroupRepository;
use ModernFields\FieldGroups\Repositories\AttachmentRepository;
use ModernFields\FieldGroups\Locations\Location;
use ModernFields\FieldGroups\Locations\UseCases\RegisterFieldsUseCase;
use ModernFields\FieldGroups\Locations\UseCases\SaveFieldsUseCase;
use ModernFields\FieldGroups\Locations\UseCases\GroupAssetsLoaderUseCase;
use ModernFields\WordPress\Security\SecurityHelper;
use ModernFields\WordPress\Interfaces\Hooks;

defined('ABSPATH') || exit;

/**
 * MediaLocation Class
 *
 * Handles the integration of Modern Fields fields into the WordPress media library attachment edit screen.
 * This class is responsible for:
 * - Registering required hooks for displaying fields on attachment edit pages
 * - Enqueuing necessary scripts and styles for the field interface
 * - Preparing and injecting inline styles for field blocks
 * - Registering attachment meta fields dynamically for REST API access
 * 
 * @since 1.0.0
 */
class MediaLocation extends Location implements Hooks
{
  /**
   * Register the WordPress hooks required for the media attachment location.
   * 
   * @since 1.0.0
   * @return void
   */
  public function registerHooks(): void
  {
    add_action('admin_init', [$this, 'registerMetaFields']);
    add_action('add_meta_boxes', [$this, 'registerMetaboxes'], 10, 2);
    add_action('admin_enqueue_scripts', [$this, 'enqueueAssets']);
    add_action('edit_attachment', [$this, 'saveFields']);
  }

  /**
   * Checks if the current admin screen is an attachment edit page.
   * 
   * @since 1.0.0
   * @return bool True if the current screen is an attachment edit page, false otherwise.
   */
  protected function isAttachmentEditPage(): bool
  {
    # Check if the current admin page is an attachment edit page
    $allowed_pages = ['post.php'];
    if (!SecurityHelper::isCurrentAdminPage($allowed_pages)) {
      return false;
    }

    # Don't add metaboxes if the post is being updated
    if (!empty($_POST)) {
      return false;
    }

    # Check if the post type is attachment
    $post_id = isset($_GET['post']) ? absint($_GET['post']) : 0;
    $post_type = get_post_type($post_id);

    if ($post_type !== 'attachment') {
      return false;
    }

    return true;
  }

  /**
   * Register attachment meta fields for the REST API
   * 
   * Dynamically registers attachment meta fields based on the field blocks found
   * in all media field groups. This allows the fields to be accessible via
   * the WordPress REST API for the frontend application.
   * 
   * @since 1.0.0
   * @return void
   */
  public function registerMetaFields(): void
  {
    if (!$this->isAttachmentEditPage()) {
      return;
    }

    $post_id = isset($_GET['post']) ? absint($_GET['post']) : 0;
    $attachment = AttachmentRepository::getAttachmentById($post_id);

    $field_groups = FieldGroupRepository::getMediaFieldGroups($attachment);

    $registerFieldsUseCase = new RegisterFieldsUseCase($field_groups);
    $registerFieldsUseCase->execute();
  }

  /**
   * Register every media field group as a metabox for attachment edit pages.
   * 
   * Only registers metaboxes for field groups that are valid for the current attachment
   * based on scope and target media types.
   * 
   * @since 1.0.0
   * @param string  $post_type The current post type being edited.
   * @param WP_Post $post      The post object currently being edited.
   * @return void
   */
  public function registerMetaboxes($post_type, $post)
  {
    if (!$this->isAttachmentEditPage()) {
      return;
    }

    $attachment = AttachmentRepository::getAttachmentById($post->ID);

    $field_groups = FieldGroupRepository::getMediaFieldGroups($attachment);

    foreach ($field_groups as $field_group) {
      add_meta_box(
        'mf-media-fields-metabox-' . $field_group->getId(),
        $field_group->getTitle(),
        [$this, 'renderMetabox'],
        'attachment',
        'normal',
        'high',
        ["group_id" => $field_group->getId()]
      );
    }

    # Remove the prepend_attachment filter to avoid unwanted content injection from media attachment images
    remove_filter('the_content', 'prepend_attachment');
  }

  /**
   * Render the metabox contents for the given field group.
   *
   * @since 1.0.0
   * @return void
   */
  public function renderMetabox($post, $metabox): void
  {
    echo '<div class="mf-media-fields-root" data-group-id="' . esc_attr($metabox['args']['group_id']) . '"></div>';
  }

  /**
   * Enqueue assets for the attachment metabox React application.
   * 
   * @since 1.0.0
   * @return void
   */
  public function enqueueAssets(): void
  {
    if (!$this->isAttachmentEditPage()) {
      return;
    }

    $attachment_id = isset($_GET['post']) ? absint($_GET['post']) : 0;
    $attachment = AttachmentRepository::getAttachmentById($attachment_id);

    $field_groups = FieldGroupRepository::getMediaFieldGroups($attachment);

    $context = [
      "attachment" => $attachment->toArray(),
    ];

    # Load assets for the media fields
    $groupAssetsLoaderUseCase = new GroupAssetsLoaderUseCase('media-fields', $field_groups, $context);
    $groupAssetsLoaderUseCase->execute();
  }

  /**
   * Save attachment fields when the media item is updated.
   *
   * @since 1.0.0
   * @param int $attachment_id The attachment ID.
   * @return void
   */
  public function saveFields($attachment_id): void
  {
    if (!SecurityHelper::checkNonce('_wpnonce', 'update-post_' . $attachment_id)) {
      return;
    }

    if (!current_user_can('edit_post', $attachment_id)) {
      return;
    }

    $attachment = AttachmentRepository::getAttachmentById($attachment_id);

    $field_groups = FieldGroupRepository::getMediaFieldGroups($attachment);

    $saveFieldsUseCase = new SaveFieldsUseCase($attachment, $field_groups);
    $saveFieldsUseCase->execute();
  }
}
