<?php
/*
Plugin Name:  Itmaroon Social Post Sync
Description:  It posts simultaneously to the three major social media platforms Twitter, Facebook, and Instagram in conjunction with WordPress posts. It also reads articles posted to these social media platforms and loads them as WordPress posts.
Requires at least: 6.4
Requires PHP:      8.2
Version:      1.0.0
Author:       Web Creator ITmaroon
Author URI:   https://itmaroon.net
License:      GPL v2 or later
License URI:  https://www.gnu.org/licenses/gpl-2.0.html
Text Domain:  itmaroon-social-post-sync
Domain Path:  /languages
*/


if (! defined('ABSPATH')) exit;

//composerパッケージの読み込み
if (file_exists(__DIR__ . '/vendor/itmar/loader-package/src/register_autoloader.php')) {
  require_once __DIR__ . '/vendor/itmar/loader-package/src/register_autoloader.php';
}

//プラグインのパス
define('ITMAR_SNS_PLUGIN_PATH', plugin_dir_path(__FILE__));
define('ITMAR_SNS_PLUGIN_URL', plugins_url('/', __FILE__));

//リレーサーバーのパス
//define('ITMAR_RELAY_SERVER_PATH', "https://itmaroon.net/relay-server");
define('ITMAR_RELAY_SERVER_PATH', "https://snstoken.local");

//Basic認証情報
const USERNAME = "";
const PASSWORD = "";


//取り込む投稿タイプを取得
$POST_GET_TYPE = get_option('postgetType', 'post');

//AWS利用のためベースURLを定義
//define('ITMAR_AWS_BASE_URL', 'https://zmttqwv1xa.execute-api.ap-northeast-1.amazonaws.com');
define('ITMAR_AWS_BASE_URL', 'https://9kwdcbx0xa.execute-api.us-east-1.amazonaws.com');

use Itmar\SNS\Tool\HttpTool;

// 管理メニューに追加
add_action('admin_menu', function () {
  $capability = 'edit_pages';

  // トップレベルメニュー：Social Post Sync
  add_menu_page(
    __('Social Post Sync', 'itmaroon-social-post-sync'),
    __('Social Post Sync', 'itmaroon-social-post-sync'),
    $capability,
    'itmaroon-social-post-sync',
    'itmar_render_sns_relate_dashboard_page',
    'dashicons-share',
    60
  );

  // サブメニュー：SNS Login
  add_submenu_page(
    'itmaroon-social-post-sync',
    __('SNS Login Setting', 'itmaroon-social-post-sync'),
    __('SNS Login Setting', 'itmaroon-social-post-sync'),
    $capability,
    'itmaroon-social-post-sync-login',
    'itmar_render_sns_login_page'
  );

  // サブメニュー：SNS Post List
  add_submenu_page(
    'itmaroon-social-post-sync',
    __('Target Post List', 'itmaroon-social-post-sync'),
    __('Target Post List', 'itmaroon-social-post-sync'),
    $capability,
    'itmaroon-social-post-sync-post-list',
    'itmar_render_sns_post_list_page'
  );

  // サブメニュー：SNS Create/Edit
  add_submenu_page(
    'itmaroon-social-post-sync',
    __('New Create Post', 'itmaroon-social-post-sync'),
    __('New Create Post', 'itmaroon-social-post-sync'),
    $capability,
    'itmaroon-social-post-sync-editor',
    'itmar_render_sns_editor_page'
  );

  // サブメニュー：Import SNS Posts
  add_submenu_page(
    'itmaroon-social-post-sync',
    __('Import SNS Posts', 'itmaroon-social-post-sync'),
    __('Import SNS Posts', 'itmaroon-social-post-sync'),
    $capability,
    'itmaroon-social-post-sync-import',
    'itmar_render_sns_import_page'
  );
});
//クラスのインスタンス化
add_action('plugins_loaded', function () {
  new \Itmar\SNS\Twitter\TokenReceiver();
  new \Itmar\SNS\Facebook\TokenReceiver();
});

//Facebookページの選択結果の保存
add_action('admin_init', function () {
  if (
    isset($_POST['itmar_fb_select_page_submit']) &&
    isset($_POST['itmar_fb_selected_page_id']) &&
    check_admin_referer('itmar_fb_select_page_action', 'itmar_fb_nonce')
  ) {
    $page_id = isset($_POST['itmar_fb_selected_page_id'])
      ? sanitize_text_field(wp_unslash($_POST['itmar_fb_selected_page_id']))
      : '';
    update_option('itmar_facebook_selected_page_id', $page_id);
  }
});
//スクリプトとスタイルのエンキュー(管理画面)
add_action('admin_enqueue_scripts', function () {

  wp_enqueue_style('swiper', ITMAR_SNS_PLUGIN_URL  . 'assets/vendor/swiper-12.0.1/swiper-bundle.min.css', array(), '12.0.1', 'all');
  wp_enqueue_style('jqtp', ITMAR_SNS_PLUGIN_URL . 'assets/vendor/jquery-datetimepicker-2.5.21/jquery.datetimepicker.min.css', array(), '2.5.21', 'all');
  $script_path = ITMAR_SNS_PLUGIN_PATH . 'css/sns_style.css';
  wp_enqueue_style('sns_style', ITMAR_SNS_PLUGIN_URL  . 'css/sns_style.css', array(), filemtime($script_path), 'all');
  $script_path = ITMAR_SNS_PLUGIN_PATH . 'css/sns_common.css';
  wp_enqueue_style('sns_common', ITMAR_SNS_PLUGIN_URL  . 'css/sns_common.css', array(), filemtime($script_path), 'all');

  wp_enqueue_script('swiper', ITMAR_SNS_PLUGIN_URL . 'assets/vendor/swiper-12.0.1/swiper-bundle.min.js', array('jquery'), '12.0.1', true);
  wp_enqueue_script('imload', ITMAR_SNS_PLUGIN_URL . 'assets/vendor/imagesloaded-5.0.0/imagesloaded.pkgd.min.js', array('jquery'), '5.0.0', true);
  wp_enqueue_script('easing', ITMAR_SNS_PLUGIN_URL . 'assets/vendor/jquery-easing-1.4.1/jquery.easing.min.js', array('jquery'), '1.4.1', true);
  wp_enqueue_script('jqdatetime', ITMAR_SNS_PLUGIN_URL . 'assets/vendor/jquery-datetimepicker-2.5.21/jquery.datetimepicker.full.min.js', array('jquery'), '2.5.21', true);
  wp_enqueue_media(); //メディアアップローダー
  $script_path = ITMAR_SNS_PLUGIN_PATH . 'js/sns_common.js';
  wp_enqueue_script('sns_relate', ITMAR_SNS_PLUGIN_URL . 'js/sns_common.js', array('jquery'), filemtime($script_path), true);


  // HTMLを必要最小限の許可タグでサニタイズ（任意）
  $allowed = array(
    'div' => array('class' => true, 'data-*' => true),
    'span' => array('class' => true),
    'a'   => array('href' => true, 'class' => true, 'target' => true, 'rel' => true),
    'img' => array('src' => true, 'alt' => true, 'class' => true),
    'p'   => array('class' => true),
    'ul'  => array('class' => true),
    'li'  => array('class' => true),
    'button' => array('class' => true, 'type' => true),
    // 必要に応じて追加
  );
  $snippets = array(
    'Twitter'   => wp_kses(itmar_disp_login_info('tw'), $allowed),
    'Facebook'  => wp_kses(itmar_disp_login_info('fb', 'min'), $allowed),
    'Instagram' => wp_kses(itmar_disp_login_info('ig'), $allowed),
  );


  // ✅ `wp_localize_script()` で  JavaScript に渡す
  wp_localize_script('sns_relate', 'sns_relate_ajax_object', [
    'plugin_uri' => ITMAR_SNS_PLUGIN_URL,
    'ajaxurl' => esc_url(admin_url('admin-ajax.php')),
    'redirectUrl' => esc_url(admin_url('admin.php')),
    'targetPostType' => get_option('postgetType', 'post'),
    'snippets' => $snippets,

    'nonce'   => wp_create_nonce('itmar-ajax-nonce') // **nonceを生成**
  ]);
});


// 各ページの表示関数
function itmar_render_sns_relate_dashboard_page()
{

?>
  <div class="wrap sns-relate-login">
    <h1 class="page_title">
      Social Post Sync <br class="sp-only"><?php esc_html_e('Dashboard', 'itmaroon-social-post-sync') ?>
    </h1><!-- /.page_title -->


    <div class="command_area">
      <div class="work_content_title">
        <?php esc_html_e('Menu Button', 'itmaroon-social-post-sync') ?>
      </div><!-- /.work_content_title -->
      <ul class="command_list">
        <li class="cmd_btn login"><a href="<?php echo esc_url(admin_url('admin.php?page=itmaroon-social-post-sync-login')); ?>">
            <?php esc_html_e('SNS login settings', 'itmaroon-social-post-sync') ?>
          </a></li><!-- /.command_item -->
        <li class="cmd_btn new_entry"><a href="<?php echo esc_url(admin_url('admin.php?page=itmaroon-social-post-sync-editor')); ?>">
            <?php esc_html_e('New SNS posts', 'itmaroon-social-post-sync') ?>
          </a></li><!-- /.command_item -->
        <li class="cmd_btn list"><a href="<?php echo esc_url(admin_url('admin.php?page=itmaroon-social-post-sync-post-list')); ?>">
            <?php esc_html_e('SNS Post List', 'itmaroon-social-post-sync') ?>
          </a></li><!-- /.command_item -->
        <li class="cmd_btn save_data"><a href="<?php echo esc_url(admin_url('admin.php?page=itmaroon-social-post-sync-import')); ?>">
            <?php esc_html_e('Import SNS posts', 'itmaroon-social-post-sync') ?>
          </a></li><!-- /.command_item -->
      </ul><!-- /.command_list -->
    </div>
  </div>
<?php
}


function itmar_render_sns_login_page()
{
  include plugin_dir_path(__FILE__) . 'sns-login-view.php';
}

function itmar_render_sns_post_list_page()
{
  include plugin_dir_path(__FILE__) . 'sns-list-view.php';
}

function itmar_render_sns_editor_page()
{
  include plugin_dir_path(__FILE__) . 'sns-editor-view.php';
}

function itmar_render_sns_import_page()
{
  include plugin_dir_path(__FILE__) . 'sns-import-view.php';
}

//ログイン情報表示
function itmar_disp_login_info($target, $min_style = null)
{

  switch ($target) {
    case 'tw': {
        $api  = new \Itmar\SNS\Twitter\ApiHelper();
        $user = $api->get_user_info();

        if (! $user) {
          $html = '<div class="user_info error">' . esc_html__('Could not retrieve Twitter login info.', 'itmaroon-social-post-sync') . '</div>';
          return $html;
        }
        if (! is_array($user)) {
          // ここがHTMLなら呼び出し側で扱われる想定。安全のため通す。
          return (string) $user;
        }

        $avatar   = esc_url($user['avatar_url'] ?? '');
        $name     = esc_html($user['name'] ?? '');
        $username = esc_html($user['username'] ?? '');

        $html  = '<div class="user_info login">';
        $html .= '<div class="image"><img src="' . $avatar . '" alt="' . $name . '"></div>';
        $html .= '<div class="text">' . $name . '<p>@' . $username . '</p></div>';
        $html .= '</div>';

        return $html;
        break;
      }

    case 'fb': {
        $api         = new \Itmar\SNS\Facebook\ApiHelper();
        $user        = $api->get_user_info();
        $pages       = $api->get_pages();
        $selected_id = $api->get_selected_page_index();

        // ヘッダー部
        $html = ($min_style === 'min') ? '' : '<div class="facebook_header menu">';

        if (empty($pages)) {
          $html .= '<div class="user_info error">' . esc_html__('No Facebook pages found. Please reconnect your account.', 'itmaroon-social-post-sync') . '</div>';
        } else {
          $html .= '<div class="user_info login">';

          if (isset($selected_id) && $selected_id !== '') {
            $selected_page = $pages[(int) $selected_id] ?? null;
            if ($selected_page) {
              $page_name = esc_html($selected_page['name'] ?? '');
              $page_icon = esc_url($selected_page['icon_url'] ?? '');
              $html     .= '<div class="image"><img src="' . $page_icon . '" alt="' . $page_name . '"></div>';
              $html     .= '<div class="text">' . $page_name . '</div>';
            }
          } else {
            $html .= '<div class="user_info error">' . esc_html__('No Facebook pages select. Please select.', 'itmaroon-social-post-sync') . '</div>';
          }

          $html .= '</div>'; // .user_info.login
        }

        $html .= ($min_style === 'min') ? '' : '</div>'; // .facebook_header menu

        if ($min_style === 'min') {
          return $html;
        }

        // ページ選択
        if (! empty($pages) && is_array($pages)) {
          $html .= '<div id="page_list">';
          $html .= '<p>－－' . esc_html__('You can change the link page to the following page:', 'itmaroon-social-post-sync') . '－－</p>';

          foreach (array_values($pages) as $index => $page) {
            $page_id   = esc_attr($page['id'] ?? '');
            $page_name = esc_html($page['name'] ?? '');
            // checked属性はWPヘルパーで安全に
            $checked_attr = checked((int) $index, (int) $selected_id, false);

            $html .= '<label>';
            $html .= '<input type="radio" name="page_radio" value="' . $page_id . '" ' . $checked_attr . '>';
            $html .= '<span>' . $page_name . '</span>';
            $html .= '</label>';
          }
          $html .= '</div>';
          $html .= '<div id="fb_entry" class="fb_btn">' . esc_html__('Change the connection page', 'itmaroon-social-post-sync') . '</div>';
        }

        // ログインユーザー情報
        $html .= '<div class="fb_user_header">';
        if (! $user) {
          $html .= '<div class="user_info error">' . esc_html__('Could not retrieve Facebook user info.', 'itmaroon-social-post-sync') . '</div>';
        } else {
          $name   = esc_html($user['name'] ?? '');
          $avatar = esc_url($user['avatar_url'] ?? '');

          $html .= '<div class="user_info">';
          $html .= '<p class="usertitle">' . esc_html__('Logged in user name:', 'itmaroon-social-post-sync') . '</p>';
          $html .= '<div class="image user_icon"><img src="' . $avatar . '" alt="' . $name . '"></div>';
          $html .= '<p class="username">' . $name . '</p>';
          $html .= '</div>'; // .user_info
        }
        $html .= '</div>'; // .fb_user_header
        $html .= '</div>'; // .fb_user_header
        // 余計な閉じコメントあったので整理
        return $html;
        break;
      }

    case 'ig': {
        $api  = new \Itmar\SNS\Instagram\ApiHelper();
        $user = $api->get_user_info();

        if (! $user) {
          $html = '<div class="user_info error">' . esc_html__('Could not retrieve Instagram login info.', 'itmaroon-social-post-sync') . '</div>';
          return $html;
        }

        $avatar   = esc_url($user['avatar_url'] ?? '');
        $name     = esc_html($user['name'] ?? '');
        $username = esc_html($user['username'] ?? '');

        $html  = '<div class="user_info login">';
        $html .= '<div class="image user_icon"><img src="' . $avatar . '" alt="' . $name . '"></div>';
        $html .= '<div class="text">' . $name . '<p>@' . $username . '</p></div>';
        $html .= '</div>';

        return $html;
        break;
      }

    default:
      $html = '<div class="user_info error">' . esc_html__('Unsupported SNS target.', 'itmaroon-social-post-sync') . '</div>';
      return $html;
  }
}


//再帰でACF画像フィールドをすべて取得
function itmar_get_all_acf_image_fields(&$error_msg = '', $grouped = true)
{
  if (!function_exists('acf_get_field_groups')) {
    $error_msg = esc_html__('ACF is not installed.', 'itmaroon-social-post-sync');
    return false;
  }

  $field_groups = acf_get_field_groups();

  if (empty($field_groups)) {
    $error_msg = esc_html__('ACF field group not found.', 'itmaroon-social-post-sync');
    return false;
  }

  $results = [];

  foreach ($field_groups as $group) {
    $fields = acf_get_fields($group['key']);
    if ($fields) {
      if ($grouped) {
        itmar_extract_image_fields_recursive($fields, $results, '', $group['title'], true);
      } else {
        itmar_extract_image_fields_recursive($fields, $results, '', '', false);
      }
    }
  }

  return $results;
}

function itmar_extract_image_fields_recursive($fields, &$results, $prefix = '', $group_label = "その他", $grouped = true)
{
  foreach ($fields as $field) {
    $full_name = $prefix ? "{$prefix}_{$field['name']}" : $field['name'];

    if (in_array($field['type'], ['group', 'repeater', 'flexible_content'])) {
      if (!empty($field['sub_fields'])) {
        $label = $field['label'] ?? $group_label;
        itmar_extract_image_fields_recursive($field['sub_fields'], $results, $full_name, $label, $grouped);
      }
    } elseif ($field['type'] === 'image') {
      $entry = [
        'name'  => $full_name,
        'label' => $field['label'],
      ];

      if ($grouped) {
        $results[$group_label][] = $entry;
      } else {
        $results[] = $entry;
      }
    }
  }
}

/**
 * ACF内のすべての画像フィールド名（スラッグ）を、グループ構造を無視して1次元配列で返す
 *
 * @return string[] 画像フィールドの完全スラッグ一覧
 */
function itmar_flat_acf_image_field_names(&$error_msg = '')
{
  if (!function_exists('acf_get_field_groups')) {
    $error_msg = esc_html__('ACF is not installed.', 'itmaroon-social-post-sync');
    return [];
  }

  $field_groups = acf_get_field_groups();
  if (empty($field_groups)) {
    $error_msg = esc_html__('ACF field group not found.', 'itmaroon-social-post-sync');
    return [];
  }

  $results = [];

  foreach ($field_groups as $group) {
    $fields = acf_get_fields($group['key']);
    if ($fields) {
      itmar_collect_image_field_names_recursive($fields, $results);
    }
  }

  return $results;
}

/**
 * 指定されたフィールド配列内から、画像フィールド名を完全スラッグで収集（非グループ）
 *
 * @param array  $fields  ACFのフィールド配列
 * @param string[] &$results フィールド名を格納する配列（参照渡し）
 * @param string $prefix  階層の接頭辞
 */
function itmar_collect_image_field_names_recursive($fields, &$results, $prefix = '')
{
  foreach ($fields as $field) {
    $full_name = $prefix ? "{$prefix}_{$field['name']}" : $field['name'];

    if (in_array($field['type'], ['group', 'repeater', 'flexible_content'], true)) {
      if (!empty($field['sub_fields'])) {
        itmar_collect_image_field_names_recursive($field['sub_fields'], $results, $full_name);
      }
    } elseif ($field['type'] === 'image' || $field['type'] === 'gallery') {
      $results[] = $full_name;
    }
  }
}


//メディアフィールド編集画面のレンダリング
function itmar_sns_image_ui($post_id)
{
  $error_msg = '';

  $media_items = itmar_get_post_media_ids($post_id, $error_msg, true);

  echo '<div class="input_image">';

  for ($i = 0; $i < 10; $i++) {
    if (isset($media_items[$i]) && !empty($media_items[$i])) {
      $media_info = $media_items[$i];
      itmar_render_image_item(['name' => $media_info['field_type'], 'label' => $media_info['label'], 'media_id' => $media_info['id']]);
    } else {
      itmar_render_image_item(['name' => 'empty', 'label' => __('Place Forlder Image', 'itmaroon-social-post-sync'), 'media_id' => '']);
    }
  }
  echo '</div><!-- /.input_image -->';
  return $media_items;
}

function itmar_render_image_item($field_data)
{
  $field_name = $field_data['name'];
  $field_label = $field_data['label'];

  $media_id    = $field_data['media_id'];
  $media_url   = '';
  $mime_type   = '';
  $width       = '';
  $height      = '';
  $is_video    = false;

  if ($media_id) {
    $mime_type = get_post_mime_type($media_id);

    if (strpos($mime_type, 'video/') === 0) {
      $media_url = wp_get_attachment_url($media_id);
      $is_video = true;

      // 動画のメタ情報からサイズを取得（存在する場合）
      $meta = wp_get_attachment_metadata($media_id);
      if (is_array($meta) && isset($meta['width'], $meta['height'])) {
        $width = $meta['width'];
        $height = $meta['height'];
      }
    } else {
      $media_url = wp_get_attachment_image_url($media_id, 'full');
      $meta = wp_get_attachment_metadata($media_id);
      if (is_array($meta) && isset($meta['width'], $meta['height'])) {
        $width = $meta['width'];
        $height = $meta['height'];
      }
    }
  }

  echo '<div class="media_item ' . ($media_url ? '' : 'empty') . '">';
  echo '  <div class="media_wrapper">';
  echo '    <div class="img_frame ' . ($media_url ? 'fill' : '') . '"'
    . ($media_id ? ' data-val="' . esc_attr($media_id) . '"' : '')
    . ' data-field="' . esc_attr($field_name) . '">';

  if ($media_url) {
    if ($is_video) {
      echo '<video autoplay loop muted playsinline src="' . esc_url($media_url) . '"'
        . ($width ? ' width="' . esc_attr($width) . '"' : '')
        . ($height ? ' height="' . esc_attr($height) . '"' : '')
        . '></video>';
    } else {
      echo '<img src="' . esc_url($media_url) . '" alt="' . esc_attr($field_label) . '"'
        . ($width ? ' width="' . esc_attr($width) . '"' : '')
        . ($height ? ' height="' . esc_attr($height) . '"' : '')
        . '>';
    }
  } else {
    echo '<img src="' . esc_url(ITMAR_SNS_PLUGIN_URL . '/img/placeholder.png') . '" alt="' . esc_attr($field_label) . '">';
  }

  echo '    </div>';
  echo '  </div>';
  echo '</div>';
}

/**
 * 指定した投稿に紐づく「ACF 画像系フィールド＋アイキャッチ画像」の
 * メディア情報オブジェクトの配列を取得する。
 *
 * 返り値の各要素は以下のような連想配列になります：
 * [
 *   'id'            => 123,                    // 添付ファイルID
 *   'field_path'    => 'profile_avatar_main',  // 親グループ名を_でつないだパス
 *   'field_type'    => 'image',                // 'image' / 'gallery' / 'featured'
 *   'meta_key'      => 'profile_avatar_main',  // post_metaのキー
 *   'acf_field_key' => 'field_XXXXXXX',        // ACFのフィールドキー
 *   'label'         => 'プロフィール画像',          // ACFのラベル
 *   'source'        => 'acf',                  // 'acf' or 'featured'
 *   'return_format' => 'id',                   // ACFのreturn_format
 *   'gallery_index' => 0,                      // gallery内の順番（galleryのみ）
 * ]
 *
 * @param int    $post_id          投稿ID
 * @param string $error_msg        エラー時のメッセージ（参照渡し）
 * @param bool   $include_featured アイキャッチ画像も含めるかどうか
 * @return array メディア情報オブジェクトの配列
 */
function itmar_get_post_media_ids($post_id, &$error_msg = '', $include_featured = true)
{
  $results = [];

  $post_id = intval($post_id);
  if (! $post_id) {
    $error_msg = esc_html__('Invalid post ID.', 'itmaroon-social-post-sync');
    return [];
  }

  // 1) アイキャッチ画像
  if ($include_featured) {
    $thumb_id = get_post_thumbnail_id($post_id);
    // alt を取得（なければタイトルを代用）
    $alt = get_post_meta($thumb_id, '_wp_attachment_image_alt', true);
    if ('' === $alt) {
      $alt = get_the_title($thumb_id);
    }
    if ($thumb_id) {
      $results[] = [
        'id'            => intval($thumb_id),
        'field_path'    => 'featured_image',   // 「アイキャッチ」とわかるキー
        'field_type'    => 'featured',
        'meta_key'      => '_thumbnail_id', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- false positive: no DB query here.
        'acf_field_key' => null,
        'label'         => $alt, // ★ alt を入れる
        'field_label'   => esc_html__('Featured image', 'itmaroon-social-post-sync'),
        'source'        => 'featured',
        'return_format' => null,
      ];
    }
  }

  // 2) ACF が無い場合はここまで
  if (! function_exists('acf_get_field')) {
    if (empty($results)) {
      $error_msg = esc_html__('ACF is not installed.', 'itmaroon-social-post-sync');
    }
    return $results;
  }

  // 3) 投稿の全 post_meta を取得
  $all_meta = get_post_meta($post_id);
  if (empty($all_meta)) {
    return $results;
  }

  foreach ($all_meta as $meta_key => $values) {
    // ACF の「フィールドキー側 meta」は _で始まるのでスキップ
    if (0 === strpos($meta_key, '_')) {
      continue;
    }

    $field_key_meta_key = '_' . $meta_key;
    if (! isset($all_meta[$field_key_meta_key][0])) {
      // ACF 管理のmetaではない
      continue;
    }

    $field_key = $all_meta[$field_key_meta_key][0];
    if (! is_string($field_key) || 0 !== strpos($field_key, 'field_')) {
      // ACFのフィールドキー形式でない
      continue;
    }

    $field = acf_get_field($field_key);
    if (! $field || empty($field['type'])) {
      continue;
    }

    $field_type = $field['type'];

    // image / gallery のみ対象
    if (! in_array($field_type, ['image', 'gallery'], true)) {
      continue;
    }

    // 値側
    $raw_value = $values[0] ?? null;
    $value     = maybe_unserialize($raw_value);

    // フィールドの「階層パス」を name ベースで構築（親group/repeater名を_でつなぐ）
    $field_path = itmar_get_acf_field_path_from_field($field);

    // このフィールドからメディア情報を抽出
    $items = itmar_extract_media_items_from_acf_value(
      $field_type,
      $field,
      $value,
      $meta_key,
      $field_path
    );

    if (! empty($items)) {
      $results = array_merge($results, $items);
    }
  }

  return $results;
}

/**
 * ACFフィールドから「階層付き field_path」を生成する。
 *
 * 例：
 *  group: profile
 *    └ field: avatar
 *  → "profile_avatar"
 *
 * repeater / flexible_content も同様に親フィールドの name を辿って _ で連結。
 *
 * @param array $field acf_get_field() の戻り値
 * @return string
 */
function itmar_get_acf_field_path_from_field($field)
{
  if (! is_array($field) || empty($field['name'])) {
    return '';
  }

  $names   = [];
  $current = $field;

  while (is_array($current) && ! empty($current['name'])) {
    // 先頭に追加していく（親 → 子 の順に並べたい）
    array_unshift($names, $current['name']);

    if (empty($current['parent'])) {
      break;
    }

    $parent_key = $current['parent'];

    // 親が field_xxx のときはさらに辿る
    if (0 === strpos($parent_key, 'field_')) {
      $parent_field = acf_get_field($parent_key);
      if (! $parent_field || ! is_array($parent_field)) {
        break;
      }
      $current = $parent_field;
    } else {
      // group_xxx（フィールドグループ）などに到達したら終了
      break;
    }
  }

  return implode('_', $names);
}

/**
 * ACF image / gallery フィールドの値からメディア情報オブジェクト配列を生成。
 *
 * @param string $field_type 'image' or 'gallery'
 * @param array  $field      acf_get_field() の戻り値
 * @param mixed  $value      get_post_meta() + maybe_unserialize() 済み値
 * @param string $meta_key   post_meta のキー
 * @param string $field_path 親フィールド名を_でつないだパス
 * @return array メディア情報オブジェクトの配列
 */
function itmar_extract_media_items_from_acf_value($field_type, $field, $value, $meta_key, $field_path)
{
  $items = [];

  if (empty($value)) {
    return [];
  }

  $return_format = isset($field['return_format']) ? $field['return_format'] : 'array';
  $acf_field_key = isset($field['key']) ? $field['key'] : null;
  $field_label         = isset($field['label']) ? $field['label'] : '';

  // -------------------------
  // image フィールド
  // -------------------------
  if ('image' === $field_type) {
    $id = null;

    if (is_array($value)) {
      if (isset($value['ID'])) {
        $id = intval($value['ID']);
      } elseif (isset($value['id'])) {
        $id = intval($value['id']);
      } elseif (isset($value['url'])) {
        $aid = attachment_url_to_postid($value['url']);
        if ($aid) {
          $id = intval($aid);
        }
      }
    } elseif (is_numeric($value)) {
      $id = intval($value);
    } elseif (is_string($value)) {
      if ('id' === $return_format && is_numeric($value)) {
        $id = intval($value);
      } elseif ('url' === $return_format) {
        $aid = attachment_url_to_postid($value);
        if ($aid) {
          $id = intval($aid);
        }
      } else {
        $maybe = maybe_unserialize($value);
        if (is_array($maybe)) {
          // 再帰的にもう一度同じ関数で処理
          return itmar_extract_media_items_from_acf_value(
            $field_type,
            $field,
            $maybe,
            $meta_key,
            $field_path
          );
        }
      }
    }

    if ($id) {
      // ★ alt を決定（配列の alt → 添付の alt → 添付タイトル）
      $alt = '';
      if (is_array($value) && ! empty($value['alt'])) {
        $alt = $value['alt'];
      }
      if ('' === $alt) {
        $alt = get_post_meta($id, '_wp_attachment_image_alt', true);
      }
      if ('' === $alt) {
        $alt = get_the_title($id);
      }

      $items[] = [
        'id'            => $id,
        'field_path'    => $field_path,
        'field_type'    => 'image',
        'meta_key'      => $meta_key, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- false positive: no DB query here.
        'acf_field_key' => $acf_field_key,
        'label'         => $alt,         // ★ label に alt を入れる
        'field_label'   => $field_label, // ACFフィールドラベルも別で保持
        'source'        => 'acf',
        'return_format' => $return_format,
      ];
    }

    return $items;
  }

  // -------------------------
  // gallery フィールド
  // -------------------------
  if ('gallery' === $field_type) {
    // 文字列で保存されている可能性に対応
    if (! is_array($value)) {
      if (is_string($value)) {
        $maybe = maybe_unserialize($value);
        if (is_array($maybe)) {
          $value = $maybe;
        } else {
          // "12,34,56" 的なID列
          $parts = array_map('trim', explode(',', $value));
          foreach ($parts as $index => $part) {
            if (is_numeric($part)) {
              $id  = intval($part);
              $alt = get_post_meta($id, '_wp_attachment_image_alt', true);
              if ('' === $alt) {
                $alt = get_the_title($id);
              }
              $items[] = [
                'id'            => intval($part),
                'field_path'    => $field_path,
                'field_type'    => 'gallery',
                'meta_key'      => $meta_key, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- false positive: no DB query here.
                'acf_field_key' => $acf_field_key,
                'label'         => $alt,        // ★ alt
                'field_label'   => $field_label,
                'source'        => 'acf',
                'return_format' => $return_format,
                'gallery_index' => $index,
              ];
            }
          }
          return $items;
        }
      } else {
        return [];
      }
    }

    // 配列の場合：画像配列 or ID配列
    foreach ($value as $index => $item) {
      $id = null;
      $alt = '';
      if (is_array($item)) {
        if (isset($item['ID'])) {
          $id = intval($item['ID']);
        } elseif (isset($item['id'])) {
          $id = intval($item['id']);
        } elseif (isset($item['url'])) {
          $aid = attachment_url_to_postid($item['url']);
          if ($aid) {
            $id = intval($aid);
          }
        } elseif (is_numeric($item)) {
          $id = intval($item);
        }
      } else {
        if (is_numeric($item)) {
          $id = intval($item);
        } elseif (is_string($item) && filter_var($item, FILTER_VALIDATE_URL)) {
          $aid = attachment_url_to_postid($item);
          if ($aid) {
            $id = intval($aid);
          }
        }
      }

      if ($id) {
        if ('' === $alt) {
          $alt = get_post_meta($id, '_wp_attachment_image_alt', true);
        }
        if ('' === $alt) {
          $alt = get_the_title($id);
        }
        $items[] = [
          'id'            => $id,
          'field_path'    => $field_path,  // 親グループ名_ギャラリー名 など
          'field_type'    => 'gallery',
          'meta_key'      => $meta_key, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- false positive: no DB query here.
          'acf_field_key' => $acf_field_key,
          'label'         => $alt,         // ★ alt
          'field_label'   => $field_label,
          'source'        => 'acf',
          'return_format' => $return_format,
          'gallery_index' => $index,
        ];
      }
    }

    return $items;
  }

  return [];
}


//カテゴリーセレクトの表示
function itmar_category_select()
{
  echo '<select name="category" class="nomal" id="id_category" multiple data-placeholder="' . esc_html__('Choose a category', 'itmaroon-social-post-sync') . '">';
  global $POST_GET_TYPE;
  $categories = [];
  $terms = [];
  $tags = [];
  $taxonomies = get_object_taxonomies($POST_GET_TYPE);


  //タクソノミーのタームを追加
  foreach ($taxonomies as $tax) {
    $tax_terms = get_terms(array(
      'taxonomy'   => $tax,
      'hide_empty' => 0 //投稿記事がないものも含める
    ));
    foreach ($tax_terms as $tax_term) {
      switch ($tax) {
        case 'post_tag':
          $tags[] = $tax_term;
          break;
        case 'category':
          $categories[] = $tax_term;
          break;
        case 'post_format':
          break;
        default:
          $terms[] = $tax_term;
      }
    }
  }
  //カテゴリの表示
  foreach ($categories as $category) {
    if ($category->term_id != 1) //未分類を除く
      echo '<option class="catg_item" value="' . esc_attr($category->slug) . '">' . esc_html($category->name) . '</option>';
  }
  //タームの表示
  foreach ($terms as $term) {
    echo '<option class="term_item" value="' . esc_attr($term->slug . ',' . $term->taxonomy) . '">' . esc_html($term->name) . '</option>';
  }
  //タグの表示
  foreach ($tags as $tag) {
    echo '<option class="tag_item" value="' . esc_attr($tag->slug) . '">' . esc_html($tag->name) . '</option>';
  }

  echo '</select><!-- /#id_category -->';
}

//全ての投稿タイプ
function itmar_get_post_types()
{
  $all_post_types = [];
  //ビルトインの投稿タイプ
  $args = array(
    'name' => 'post'
  );
  $post_types = get_post_types($args, 'objects');
  foreach ($post_types  as $post_type) {
    $all_post_types[] = $post_type;
  }
  //カスタム投稿タイプ
  $args = array(
    'public'   => true,
    '_builtin' => false
  );
  $post_types = get_post_types($args, 'objects');
  foreach ($post_types  as $post_type) {
    $all_post_types[] = $post_type;
  }

  return $all_post_types;
}

//Wordpressオプションに記録
add_action('wp_ajax_itmar_option_entry', function () {
  check_ajax_referer('itmar-ajax-nonce', 'nonce');

  $option_name = isset($_POST['option_name'])
    ? sanitize_key(wp_unslash($_POST['option_name']))
    : '';
  $option_val = isset($_POST['option_val'])
    ? sanitize_key(wp_unslash($_POST['option_val']))
    : '';

  update_option($option_name, $option_val);
  //グローバル変数の書き換え
  if ($option_name === 'postgetType') {
    global $POST_GET_TYPE;
    $POST_GET_TYPE = $option_val;
  }
  die();
});

//autodraftの削除
add_action('wp_ajax_itmar_del_pending', function () {
  check_ajax_referer('itmar-ajax-nonce', 'nonce');

  $del_id = isset($_POST['del_id'])
    ? sanitize_key(wp_unslash($_POST['del_id']))
    : '';
  $post_obj = get_post($del_id);
  $post_status = $post_obj->post_status;
  if ($post_status === 'pending') {
    wp_delete_post($del_id, true);
  }
});

//翻訳処理
function itmar_url_trans_ajax()
{
  check_ajax_referer('itmar-ajax-nonce', 'nonce');

  $input_data = isset($_POST['input_data'])
    ? sanitize_text_field(wp_unslash($_POST['input_data']))
    : '';
  $post_id = isset($_POST['post_id'])
    ? sanitize_key(wp_unslash($_POST['post_id']))
    : '';

  if (function_exists('sl_trans_exec_translate')) { //翻訳関数が存在するか
    $post_obj = get_post($post_id);
    $ret_data = sl_trans_exec_translate($input_data);
    if ($ret_data['code'] == 0) { //翻訳が成功したら
      $ret_name = $ret_data['text'];
      $sani_data = sanitize_title_with_dashes($ret_name); //サニタイズする
      $uni_data = wp_unique_post_slug($sani_data, $post_id, $post_obj->post_status, $post_obj->post_type, 0); //ユニークなURLに変換
      $ret_data['text'] = $uni_data;
    }
  }
  wp_send_json_success($ret_data);
}
add_action('wp_ajax_itmar_url_trans', 'itmar_url_trans_ajax');
add_action('wp_ajax_nopriv_itmar_url_trans', 'itmar_url_trans_ajax');

//画像等のURL取得
function itmar_get_imgUrl_ajax()
{
  check_ajax_referer('itmar-ajax-nonce', 'nonce');

  $img_id = isset($_POST['img_id'])
    ? sanitize_key(wp_unslash($_POST['img_id']))
    : '';
  $index = isset($_POST['index'])
    ? sanitize_key(wp_unslash($_POST['index']))
    : '';
  $meta    = wp_get_attachment_metadata($img_id); // メタデータを取得
  $ret_arr = [];

  if (isset($meta['mime_type']) && $meta['mime_type'] === 'video/mp4') {
    // 動画本体のURL
    $video_url = wp_get_attachment_url($img_id);

    // もしこの動画にサムネイル画像が生成されていれば取得（なければ false）
    // 'thumbnail' でも 'medium' でもお好みでOK
    $thumb = wp_get_attachment_image_src($img_id, 'medium');

    $ret_arr = array(
      'index'  => $index,
      'url'    => $video_url,
      'width'  => $meta['width']  ?? null, // 動画の幅
      'height' => $meta['height'] ?? null, // 動画の高さ
      'kind'   => 'video',
      'type'   => $meta['mime_type'],
    );

    // サムネイル情報を付与（あるときだけ）
    if ($thumb) {
      // $thumb = [ 0 => URL, 1 => width, 2 => height, 3 => is_intermediate ]
      $ret_arr['thumb'] = array(
        'url'    => $thumb[0],
        'width'  => $thumb[1],
        'height' => $thumb[2],
      );
    }
  } else {
    // 画像など（従来の処理）
    $img_url = wp_get_attachment_image_url($img_id, 'full');

    $mime = null;
    if (! empty($meta['sizes']['medium']['mime-type'])) {
      $mime = $meta['sizes']['medium']['mime-type'];
    } else {
      // 念のためフォールバック
      $mime = get_post_mime_type($img_id);
    }

    $ret_arr = array(
      'index'  => $index,
      'url'    => $img_url,
      'width'  => $meta['width']  ?? null,
      'height' => $meta['height'] ?? null,
      'kind'   => 'image',
      'type'   => $mime,
    );
  }

  wp_send_json_success($ret_arr);
}
add_action('wp_ajax_itmar_get_imgUrl', 'itmar_get_imgUrl_ajax');
add_action('wp_ajax_nopriv_itmar_get_imgUrl', 'itmar_get_imgUrl_ajax');

//sns投稿ステータスの表示
function itmar_disp_sns_status($status)
{
  if (is_null($status)) {
    echo '<div class="status_err">' . esc_html_e('Status acquisition failed', 'itmaroon-social-post-sync') . '</div>';
    return;
  }
  if (is_array($status) && $status['response']) {
    echo '<div class="status_err">' . esc_html($status['response']['message']) . '</div>';
    return;
  }
  $status_arr = explode(',', $status);
  if (count($status_arr) > 1 && $status_arr[0] === 'ERROR') {
    echo '<div class="status_err">' . esc_html($status_arr[1]) . '</div>';
  } elseif (count($status_arr) > 1 && $status_arr[0] === 'RESERVE') {
    echo '<div class="status_reserve">' . esc_html($status_arr[1]) . '</div>';
  } elseif (count($status_arr) > 1 && $status_arr[0] === 'WAIT') {
    echo '<div class="status_wait">' . esc_html($status_arr[1]) . '</div>';
  } else {
    echo '<div>' . esc_html($status) . '</div>';
  }
}

//ページネーション
function itmar_sns_pagenation($max_page)
{
  // ページ数が1以下なら表示不要
  if ($max_page <= 1) {
    return;
  }

  $bignum = 999999999;

  // 現在のページ番号をサニタイズして取得
  //$current_page = isset($_GET['paged']) ? max(1, absint($_GET['paged'])) : 1;
  $current_page = (int) get_query_var('paged');
  if ($current_page < 1) {
    // 管理画面などでquery varが立っていない場合のフォールバック
    $current_page = isset($_GET['paged'])
      ? max(1, absint(wp_unslash($_GET['paged'])))
      : 1; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only pagination parameter; no state change.
  }

  // ページネーションを生成
  $pagination = paginate_links(array(
    'base'      => str_replace($bignum, '%#%', esc_url(get_pagenum_link($bignum))),
    'format'    => '',
    'current'   => $current_page,
    'total'     => $max_page,
    'prev_text' => '&lt;', // 安全に表示
    'next_text' => '&gt;', // 安全に表示
    'type'      => 'list',
    'end_size'  => 1,
    'mid_size'  => 1,
  ));

  // ページネーションが生成された場合のみ表示
  if ($pagination) {
    echo '<nav class="snslist_pagination">';
    echo wp_kses_post($pagination); // paginate_links は内部でエスケープ済み
    echo '</nav>';
  }
}


//wp投稿を削除する
function itmar_delete_sns_ajax()
{
  check_ajax_referer('itmar-ajax-nonce', 'nonce');

  $del_id = isset($_POST['del_id'])
    ? sanitize_key(wp_unslash($_POST['del_id']))
    : '';
  $del_sns = isset($_POST['del_sns'])
    ? sanitize_key(wp_unslash($_POST['del_sns']))
    : '';

  switch ($del_sns) {
    case 'twitter_id':
      $id = get_post_meta($del_id, 'twitter_id', true);
      if (!is_null($id)) {
        $helper = new \Itmar\SNS\Twitter\ApiHelper();
        $res = $helper->delete_post($id);
      } else {
        $res = null;
      }
      break;
    case 'facebook_id':
      $id = get_post_meta($del_id, 'facebook_id', true);
      if (!is_null($id)) {
        $helper = new \Itmar\SNS\Facebook\ApiHelper();
        $res = $helper->delete_post($id);
      } else {
        $res = null;
      }
      break;
    case 'instagram_id':
      // $id = get_post_meta($del_id, 'instagram_id', true);
      // if (!is_null($id)) {
      //   $helper = new \Itmar\SNS\Instagram\ApiHelper();
      //   $res = $helper->delete_post($id);
      // } else {
      //   $res = null;
      // }
      break;
    case 'wp_id':
      $res = wp_delete_post($del_id, false);
      break;
  }

  if ($res->errors || is_null($res) || $res == false) echo 'ERROR,' . esc_html__('Deletion failed.', 'itmaroon-social-post-sync');
  else echo 'SUCCESS,' . esc_html__('It has been deleted.', 'itmaroon-social-post-sync');

  die();
}
add_action('wp_ajax_itmar_del_sns', 'itmar_delete_sns_ajax');
add_action('wp_ajax_noprivitmar__del_sns', 'itmar_delete_sns_ajax');

function itmar_entry_sns_ajax()
{
  check_ajax_referer('itmar-ajax-nonce', 'nonce');
  $entry_ID = isset($_POST['entry_ID'])
    ? sanitize_key(wp_unslash($_POST['entry_ID']))
    : '';
  $entry_text = isset($_POST['entry_text'])
    ? sanitize_text_field(wp_unslash($_POST['entry_text']))
    : '';
  // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash
  $entry_img_raw = isset($_POST['entry_img']) ? $_POST['entry_img'] : array();
  $entry_img     = itmar_sanitize_entry(wp_unslash($entry_img_raw));
  // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash
  $entry_video_raw = isset($_POST['entry_video']) ? $_POST['entry_video'] : array();
  $entry_video     = itmar_sanitize_entry(wp_unslash($entry_video_raw));
  $entry_sns = isset($_POST['entry_sns'])
    ? sanitize_text_field(wp_unslash($_POST['entry_sns']))
    : '';

  // 📌 先に応答だけ返す
  ignore_user_abort(true); // 接続が切れても処理継続
  header('Content-Type: application/json');
  echo json_encode(['status' => 'queued']);

  if (function_exists('fastcgi_finish_request')) {
    fastcgi_finish_request(); // ✅ FPM環境なら応答を即終了
  } else {
    // ✅ FPM以外の環境では出力をフラッシュして手動で応答終了
    flush();
    if (function_exists('ob_flush')) ob_flush();
  }
  // 📌 投稿処理をバックグラウンドで開始
  $array_sns_option = [
    'ID'    => $entry_ID,
    'text'  => $entry_text,
    'img'   => $entry_img,
    'video' => $entry_video,
    'sns'   => $entry_sns,
  ];

  //送信処理
  itmar_post_sns($array_sns_option);
}
add_action('wp_ajax_itmar_entry_sns', 'itmar_entry_sns_ajax');
add_action('wp_ajax_nopriv_itmar_entry_sns', 'itmar_entry_sns_ajax');

//メディアの連想配列サニタイズ関数
function itmar_sanitize_entry($value)
{
  if (is_array($value)) {
    $out = array();
    foreach ($value as $k => $v) {
      if (is_array($v)) {
        $out[$k] = itmar_sanitize_entry($v);
        continue;
      }
      switch ($k) {
        case 'id':
        case 'attachment_id':
          $out[$k] = absint($v);
          break;
        case 'url':
        case 'src':
          $out[$k] = esc_url_raw($v);
          break;
        case 'alt':
        case 'title':
          $out[$k] = sanitize_text_field($v);
          break;
        case 'caption':
        case 'description':
          $out[$k] = sanitize_textarea_field($v);
          break;
        default:
          // 想定外キーは基本テキスト扱い（または捨てるなら unset）
          $out[$k] = sanitize_text_field($v);
      }
    }
    return $out;
  }
  return sanitize_text_field((string) $value);
}

//SNS投稿処理
function itmar_post_sns($option)
{

  $media_arr = [];
  $media_url = '';
  //イメージ配列の取得

  $key_list = array_keys(array_column($option['img'], 'target'), $option['sns']);
  foreach ($key_list as $index) {
    $media_url = $option['img'][$index]['url'];
    $media_arr[] = ['type' => 'img', 'url' => $media_url];
  }
  //ビデオ配列の取得

  $key_list = array_keys(array_column($option['video'], 'target'), $option['sns']);
  foreach ($key_list as $index) {
    $media_url = $option['video'][$index]['url'];
    $media_arr[] = ['type' => 'video', 'url' => $media_url];
  }
  //投稿処理
  $ret_id_name = "";
  $helper = null;
  switch ($option['sns']) {
    case 'Twitter':
      $ret_id_name = 'twitter_id';
      $helper = new \Itmar\SNS\Twitter\ApiHelper();

      break;
    case 'Facebook':
      $ret_id_name = 'facebook_id';
      $helper = new \Itmar\SNS\Facebook\ApiHelper();
      break;
    case 'Instagram':
      $ret_id_name = 'instagram_id';
      $helper = new \Itmar\SNS\Instagram\ApiHelper();
      break;
  }
  //投稿処理待ちであることをフィールドに入力
  update_post_meta($option['ID'], $ret_id_name, 'WAIT,' . esc_html__('Processing post...', 'itmaroon-social-post-sync'));
  //投稿実行
  if (!is_null($helper)) {
    $ret_val = $helper->create_post($option['ID'], $option['text'], $media_arr);
  }

  // 結果が WP_Error ならメッセージを保存、job_idを含んでいればそのまま、それ以外は投稿IDとして保存
  if (is_wp_error($ret_val)) {
    $error_message = $ret_val->get_error_message();
    update_post_meta($option['ID'], $ret_id_name, 'ERROR,' . $error_message);
  } else {
    $body = wp_remote_retrieve_body($ret_val);
    $data = json_decode($body, true); // JSONを配列に変換

    if (isset($data['job_id'])) {
      // job_idが存在する場合
      return;
    } else {
      update_post_meta($option['ID'], $ret_id_name, $ret_val);
    }
  }
}

//sns投稿結果取得（AWSから）
add_filter('get_post_metadata', 'itmar_sync_status_on_read', 10, 3);
function itmar_sync_status_on_read($value, $post_id, $meta_key)
{
  //必要なmetaキー以外はスルー
  if ($meta_key !== 'twitter_id' && $meta_key !== 'instagram_id') {
    return $value;
  }

  // ---- キャッシュ取得 ----
  $cached_jobs = get_transient('itmar_convert_jobs_cache');
  if ($cached_jobs === false) {
    // キャッシュが無ければAWSから取得
    $result = HttpTool::jobs_result_request();
    if (is_wp_error($result)) {
      //エラーをキャッシュに保存
      set_transient('itmar_convert_jobs_cache', $result, 0.5 * MINUTE_IN_SECONDS);
      return $value; // AWSエラー → 既存値を返す
    }

    if (!empty($result['jobs'])) {
      $cached_jobs = $result['jobs'];
      set_transient('itmar_convert_jobs_cache', $cached_jobs, 0.5 * MINUTE_IN_SECONDS);
    } else {
      // ジョブなしなら終了
      return $value;
    }
  }
  //キャッシュにエラーが入っていれば既存値を返す
  if (is_wp_error($cached_jobs)) {
    return $value;
  }

  // ---- 該当post_idのジョブを検索 ----
  $found = null;
  foreach ($cached_jobs as $job) {
    if ((string)$job['wp_id'] === (string)$post_id) {
      // プラットフォームを確認（X or Instagram）
      $platform = $job['platform'] ?? '';
      if (
        ($meta_key === 'twitter_id' && $platform === 'X') ||
        ($meta_key === 'instagram_id' && $platform === 'ig')
      ) {
        $found = $job;
        break;
      }
    }
  }

  // ---- ステータスの解析 ----
  $status = $found['status'] ?? '';
  $ret_str = $value;

  if ($status === 'pending' || $status === '') {
    // 進行中
    $ret_str = $value;
  } elseif (stripos($status, 'ERROR,') === 0) {
    $ret_str = 'ERROR,投稿失敗: ' . $status;
  } else {
    // 成功または投稿ID
    $ret_str = $status;
  }
  if ($ret_str !== $value) {
    // ---- 永続保存の無限ループ回避 ----
    // update_post_metaを直接呼ぶとこのフィルターが再発火するため、
    // フックを一時的に削除してから実行
    remove_filter('get_post_metadata', 'itmar_sync_status_on_read', 10);

    update_post_meta($post_id, $meta_key, $ret_str);
    // ✅ DynamoDB項目削除
    try {
      $api_base = rtrim(ITMAR_AWS_BASE_URL, '/');
      $site_url = site_url();
      wp_remote_request($api_base . "/jobs/{$job['job_id']}", [
        'method'  => 'DELETE',
        'timeout' => 10,
        'headers' => [
          'x-site-url' => $site_url,
          'x-wp-id' => $job['wp_id'],
          'Content-Type' => 'application/json',
        ],
      ]);
    } catch (Exception $e) {
      error_log('DynamoDB delete failed: ' . $e->getMessage());
    }
    add_filter('get_post_metadata', 'itmar_sync_status_on_read', 10, 3);
  }
  return $ret_str;
}

//SNS投稿取得処理
function itmar_get_sns_ajax()
{
  check_ajax_referer('itmar-ajax-nonce', 'nonce');
  $after    = isset($_REQUEST['after']) ? sanitize_text_field(wp_unslash($_REQUEST['after'])) : null;
  $sns_type = isset($_REQUEST['sns_type']) ? sanitize_text_field(wp_unslash($_REQUEST['sns_type'])) : null;
  $limit    = isset($_REQUEST['limit']) ? intval($_REQUEST['limit']) : 10;

  if ($sns_type === 'facebook') {
    $api = new \Itmar\SNS\Facebook\ApiHelper();
    $result = $api->get_post($limit, $after);

    $res_arr = [];

    foreach ($result['data'] as $json) {
      $objDateTime = new DateTime($json["created_time"]);
      $objDateTime->setTimeZone(new DateTimeZone('Asia/Tokyo'));
      $date = $objDateTime->format('Y-m-d G:i');

      $favorite_count = $json['reactions']['summary']['total_count'] ?? 0;

      $res_arr[] = [
        'date'     => $date,
        'favarit'  => $favorite_count,
        'sns_kind' => 'facebook',
        'sns_obj'  => $json
      ];
    }

    wp_send_json([
      'items'      => $res_arr,
      'next_after' => $result['paging'] ?? null,
    ]);
  } elseif ($sns_type === 'instagram') {
    $api = new \Itmar\SNS\Instagram\ApiHelper();
    $result = $api->get_post($limit, $after);

    $res_arr = [];

    foreach ($result['data'] as $json) {
      $objDateTime = new DateTime($json["timestamp"]);
      $objDateTime->setTimeZone(new DateTimeZone('Asia/Tokyo'));
      $date = $objDateTime->format('Y-m-d G:i');

      $res_arr[] = [
        'date'     => $date,
        'favarit'  => null, // Instagramはいいね数取得できないため
        'sns_kind' => 'instagram',
        'sns_obj'  => $json
      ];
    }

    wp_send_json([
      'items'      => $res_arr,
      'next_after' => $result['paging'] ?? null,
    ]);
  }

  wp_send_json_error(['message' => 'Unsupported sns_type']);
}

add_action('wp_ajax_itmar_get_sns', 'itmar_get_sns_ajax');
add_action('wp_ajax_nopriv_itmar_get_sns', 'itmar_get_sns_ajax');

function itmar_get_ids_ajax()
{
  // セキュリティチェック
  check_ajax_referer('itmar-ajax-nonce', 'nonce');

  // パラメータ取得
  $sns_name = isset($_POST['sns_name'])
    ? sanitize_text_field(is_array(wp_unslash($_POST['sns_name'])) ? '' : wp_unslash($_POST['sns_name']))
    : '';
  $post_type = isset($_POST['post_type'])
    ? sanitize_text_field(is_array(wp_unslash($_POST['post_type'])) ? '' : wp_unslash($_POST['post_type']))
    : '';

  if (empty($sns_name) || empty($post_type)) {
    wp_send_json_error(['message' => 'Missing parameters']);
  }

  // 投稿IDのみ取得（軽量化）
  $args = [
    'posts_per_page' => -1,
    'post_type'      => $post_type,
    'fields'         => 'ids',
    'post_status'    => 'any', // 公開済み・下書きなどすべて対象
  ];
  $post_ids = get_posts($args);

  // SNS IDの配列を構築
  $sns_ids = [];
  foreach ($post_ids as $post_id) {
    $id = get_post_meta($post_id, $sns_name, true);
    if (!empty($id)) {
      $sns_ids[] = $id;
    }
  }

  // JSONで返却（Content-Typeヘッダと exit() 含む）
  wp_send_json($sns_ids);
}

add_action('wp_ajax_itmar_get_ids', 'itmar_get_ids_ajax');
add_action('wp_ajax_nopriv_itmar_get_ids', 'itmar_get_ids_ajax');

//SNSからWordPressに取り込む処理
function itmar_post_wp_ajax()
{
  // WordPress の nonce チェック（セキュリティ対策）
  check_ajax_referer('itmar-ajax-nonce', 'nonce');

  $db_obj = new \Itmar\WpsettingClassPackage\ItmarDbAction();


  // **JSON をデコード**
  $post_data = [];

  if (isset($_POST['post_data'])) {
    $raw_json = wp_unslash($_POST['post_data']); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
    $decoded  = json_decode($raw_json, true);

    if (is_array($decoded)) {
      $post_data = $decoded;
    }
  }

  // **デコードエラーチェック**
  if (!is_array($post_data) || empty($post_data)) {
    wp_send_json_error(["message" => __("Incorrect data", "itmaroon-social-post-sync")]);
    exit;
  }
  //インポートするメディアファイル情報
  $import_files = [];
  // アイキャッチ画像（単体）
  $featured_file = [];
  if (isset($_FILES['featured_image']) && $_FILES['featured_image']['error'] === 0) {
    $featured_file = itmar_sanitize_files($_FILES['featured_image']);
  }
  //acf画像フィールド
  $acf_files = [];
  if (isset($_FILES['featured_image']) && $_FILES['featured_image']['error'] === 0) {
    $acf_image_fields = itmar_flat_acf_image_field_names($error); //acf画像フィールドの取得
    $acf_files = itmar_sanitize_files($_FILES['media_files']);

    //acfフィールドの配列生成
    $field_key = '';
    foreach ($acf_files as $index => $import_file) {
      $field_key = $field_key === 'gallery' ? 'gallery' : $acf_image_fields[$index];
      $value     = '/exported_media/' . $import_file['name'];

      if ($field_key === 'gallery') {
        // 新しい値を配列に追加
        $acf_field[$field_key][] = $value;
      } else {
        //スカラーで追加
        $acf_field[$field_key] = $value;
      }
    }
    $post_data['acf_fields'] = $acf_field;
  }

  //画像情報を併せる
  $import_files = array_merge($featured_file, $acf_files);

  //もう一つ配列に入れる
  $all_data = [];
  $all_data[] = $post_data;

  //挿入モードか更新モードか
  $mode = isset($_POST['mode']) ? sanitize_text_field(wp_unslash($_POST['mode'])) : 'update';
  //データベース処理の実行
  $result = $db_obj->json_import_data($all_data, $import_files, $mode);
  //ACFフィールド保存
  wp_send_json($result);
}
add_action('wp_ajax_itmar_post_ajax', 'itmar_post_wp_ajax');
add_action('wp_ajax_nopriv_itmar_post_ajax', 'itmar_post_wp_ajax');

function itmar_sanitize_files($files)
{
  $sanitized_files = [];
  if (isset($files) && isset($files['name'])) {
    if (is_array($files) && is_array($files['name'])) {
      $file_count = count($files['name']);
      for ($i = 0; $i < $file_count; $i++) {
        // 各フィールドの存在をチェックしてから処理
        $name      = isset($files['name'][$i]) ? sanitize_file_name(wp_unslash($files['name'][$i])) : '';
        $type      = isset($files['type'][$i]) ? sanitize_mime_type(wp_unslash($files['type'][$i])) : '';
        $tmp_name = isset($files['tmp_name'][$i])
          ? $files['tmp_name'][$i] // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
          : '';
        $error     = isset($files['error'][$i]) ? (int) $files['error'][$i] : 1; // デフォルトをエラー扱いに
        $size      = isset($files['size'][$i]) ? absint($files['size'][$i]) : 0;
        // ファイル構造再現用に full_path を取得。保存/表示目的で使用。
        $full_path = isset($files['full_path'][$i])
          ? $files['full_path'][$i] // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
          : '';

        // エラーファイルはスキップしてもよい
        if ($error === 0 && $name && $tmp_name) {
          $sanitized_files[] = [
            'name'       => $name,
            'type'       => $type,
            'tmp_name'   => $tmp_name,
            'error'      => $error,
            'size'       => $size,
            'full_path'  => $full_path,
          ];
        }
      }
    } else {
      $name      = isset($files['name']) ? sanitize_file_name(wp_unslash($files['name'])) : '';
      $type      = isset($files['type']) ? sanitize_mime_type(wp_unslash($files['type'])) : '';
      $tmp_name = isset($files['tmp_name'])
        ? $files['tmp_name'] // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
        : '';
      $error     = isset($files['error']) ? (int) $files['error'] : 1; // デフォルトをエラー扱いに
      $size      = isset($files['size']) ? absint($files['size']) : 0;
      // ファイル構造再現用に full_path を取得。保存/表示目的で使用。
      $full_path = isset($files['full_path'])
        ? $files['full_path'] // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
        : '';

      // エラーファイルはスキップしてもよい
      if ($error === 0 && $name && $tmp_name) {
        $sanitized_files[] = [
          'name'       => $name,
          'type'       => $type,
          'tmp_name'   => $tmp_name,
          'error'      => $error,
          'size'       => $size,
          'full_path'  => $full_path,
        ];
      }
    }
  }

  return $sanitized_files;
}
