<?php

namespace ModernFields\FieldGroups\Locations\Hooks;

use ModernFields\FieldGroups\Entities\FieldGroup;
use ModernFields\FieldGroups\Entities\Post;
use ModernFields\FieldGroups\Locations\AbstractPostLocation;
use ModernFields\FieldGroups\Locations\UseCases\SaveFieldsUseCase;
use ModernFields\FieldGroups\Repositories\FieldGroupRepository;
use ModernFields\FieldGroups\Repositories\PostRepository;
use ModernFields\WordPress\Security\SecurityHelper;
use ModernFields\WordPress\Interfaces\Hooks;

defined('ABSPATH') || exit;

/**
 * ClassicPostLocation Class
 *
 * Handles Modern Fields field groups on post types that use the classic editor
 * (e.g. WooCommerce products, or any CPT where the block editor is disabled).
 *
 * The core/editor store does not exist on these screens, so the React fields
 * cannot save through editPost. Instead they render plain form inputs
 * (name="modern_fields_*") inside the classic post form, exactly like the user,
 * media and term locations, and the submitted values are persisted on save_post
 * through SaveFieldsUseCase.
 *
 * Since the classic editor has no plugin sidebar, inspector-positioned groups
 * are rendered as side metaboxes (right column) instead.
 *
 * @since 1.1.0
 */
class ClassicPostLocation extends AbstractPostLocation implements Hooks
{
  /**
   * Register the shared hooks plus the classic save handler.
   *
   * @since 1.1.0
   * @return void
   */
  public function registerHooks(): void
  {
    parent::registerHooks();
    add_action('save_post', [$this, 'saveFields'], 10, 2);
  }

  /**
   * Only handle post types whose edit screen is the classic editor.
   *
   * @since 1.1.0
   * @param string $post_type The post type being edited.
   * @return bool
   */
  protected function shouldHandlePostType(string $post_type): bool
  {
    return !use_block_editor_for_post_type($post_type);
  }

  /**
   * Register every group as a metabox: inspector groups go to the right column
   * ('side'), all others to the main column ('normal').
   *
   * @since 1.1.0
   * @param FieldGroup $field_group The field group to place.
   * @return string|null
   */
  protected function getMetaboxContext(FieldGroup $field_group): ?string
  {
    return $field_group->getPosition() === 'inspector' ? 'side' : 'normal';
  }

  /**
   * The classic post fields bundle.
   *
   * @since 1.1.0
   * @return string
   */
  protected function getBundleName(): string
  {
    return 'classic-post-fields';
  }

  /**
   * Inject the post meta so the React state can seed itself from the saved
   * values — there is no editor store to read from on classic screens.
   *
   * @since 1.1.0
   * @param Post $post The post being edited.
   * @return array<string, mixed>
   */
  protected function buildContext(Post $post): array
  {
    return array_merge(parent::buildContext($post), [
      "post" => $post->toArray(),
    ]);
  }

  /**
   * Persist the submitted field values when a classic post is saved.
   *
   * The nonce check runs first so REST-based block editor saves (which carry no
   * classic post nonce) bail out before use_block_editor_for_post_type() is ever
   * called — that function lives in wp-admin and is not loaded during REST.
   *
   * @since 1.1.0
   * @param int      $post_id The post being saved.
   * @param \WP_Post $post    The post object being saved.
   * @return void
   */
  public function saveFields($post_id, $post): void
  {
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
      return;
    }

    if (wp_is_post_revision($post_id)) {
      return;
    }

    if (!SecurityHelper::checkNonce('_wpnonce', 'update-post_' . $post_id)) {
      return;
    }

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

    $post_type = get_post_type($post_id);

    if (in_array($post_type, $this->getExcludedPostTypes(), true) || !$this->shouldHandlePostType($post_type)) {
      return;
    }

    $post = PostRepository::getPostById($post_id);
    $field_groups = FieldGroupRepository::getPostsFieldGroups($post);

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