<?php

namespace Pixalia\ImageAssistant\Service;

use Pixalia\ImageAssistant\Admin\View\PostListStatusTabs;
use Pixalia\ImageAssistant\Base\Const\MetaKeyConst;
use Pixalia\ImageAssistant\Base\Const\PixaliaConst;
use Pixalia\ImageAssistant\Base\Enum\ImageCheck\ImageCheckResultStatusEnum;
use Pixalia\ImageAssistant\Base\Enum\ImageCheck\ImageSetFromEnum;
use Pixalia\ImageAssistant\Service\Container\ImageCheckResult;
use Pixalia\ImageAssistant\Repository\PostRepository;

/**
 * ImageChecker Class
 *
 * 投稿のアイキャッチ画像やOGP画像の設定状況をチェックし、
 * 'ok', 'warning', 'ng' のステータスを判定します。
 *
 * 対応プラグイン・テーマ:
 * - All in One SEO (AIOSEO)
 * - Yoast SEO
 * - SEO SIMPLE PACK
 * - SWELL テーマ
 * - Cocoon テーマ
 *
 * @since 1.0.0
 * @version 1.1.0 SWELL/Cocoon対応追加
 * @version 1.2.0 PostRepository統合
 */
class ImageChecker {

	/**
	 * SEOプラグイン・テーマの判定設定
	 *
	 * 優先度: 数値が小さいほど優先（1が最優先）
	 *
	 * 優先順位の考え方:
	 * 1. SEOプラグイン（明示的なSEO設定）
	 * 2. テーマ独自のOGP設定（テーマレベルの設定）
	 * 3. WordPress標準
	 */
	private const SEO_PLUGINS_CONFIG = [
		'aioseo' => [
			'type' => 'plugin',
			'class' => 'AIOSEO\Core\AIOSEO',
			'priority' => 1,
		],
		'yoast' => [
			'type' => 'plugin',
			'class' => 'WPSEO_Meta',
			'priority' => 1,
		],
		'seo_simple_pack' => [
			'type' => 'plugin',
			'class' => null,
			'priority' => 2,
		],
		'swell' => [
			'type' => 'theme',
			'template' => 'swell',
			'priority' => 3,
		],
		'cocoon' => [
			'type' => 'theme',
			'template' => 'cocoon-master',
			'priority' => 3,
		],
	];

	// プラグイン用メタキー定数
	private const AIOSEO_OG_IMAGE_TYPE = '_aioseo_og_image_type';
	private const AIOSEO_OG_IMAGE_URL = '_aioseo_og_image_custom_url';
	private const YOAST_OG_IMAGE = '_yoast_wpseo_opengraph-image';
	private const YOAST_OG_IMAGE_ID = '_yoast_wpseo_opengraph-image-id';
	private const SSP_OG_IMAGE_URL = 'ssp_meta_ogp_image_url';

	// テーマ用メタキー定数
	private const SWELL_OGP_IMAGE = 'swell_ogp_img';
	private const COCOON_OG_IMAGE = 'og_image';

	/**
	 * キャッシュ: アクティブなテーマ情報
	 *
	 * @var string|null
	 */
	private static ?string $activeTemplate = null;

	/**
	 * PostRepository インスタンス
	 *
	 * @var PostRepository
	 */
	private PostRepository $postRepository;

	/**
	 * コンストラクタ
	 *
	 * @param PostRepository|null $postRepository 依存性注入用（テスト時にモック可能）
	 */

	public function __construct( ?PostRepository $postRepository = null ) {
		$this->postRepository = $postRepository ?? new PostRepository();
	}

	/**
	 * 指定された投稿IDの画像設定状況をチェックします。
	 *
	 * チェック優先順位:
	 * 1. SEOプラグイン（AIOSEO/Yoast SEO）- 最優先
	 * 2. SEO SIMPLE PACK
	 * 3. テーマ独自設定（SWELL/Cocoon）
	 * 4. WordPress標準アイキャッチ
	 * 5. 本文中の画像（Warning）
	 * 6. 未設定（NG）
	 *
	 * @param int $postId 投稿ID
	 * @return ImageCheckResult チェック結果のオブジェクト
	 */
	public function check( int $postId ): ImageCheckResult {
		// SEOプラグイン・テーマのチェック（優先度順）
		$checkers = $this->getCheckers();

		foreach ( $checkers as $checker ) {
			$result = $checker( $postId );
			if ( $result !== null ) {
				return $result;
			}
		}

		// WordPress標準のアイキャッチ画像チェック
		if ( has_post_thumbnail( $postId ) ) {
			return new ImageCheckResult(
				ImageCheckResultStatusEnum::OK,
				ImageSetFromEnum::WordPress
			);
		}

		// 本文中に画像が存在するか（フォールバック可能性）
		if ( $this->hasImageInContent( $postId ) ) {
			return new ImageCheckResult(
				ImageCheckResultStatusEnum::WARNING,
				ImageSetFromEnum::PostContent
			);
		}

		// 完全に未設定
		return new ImageCheckResult(
			ImageCheckResultStatusEnum::NG,
			ImageSetFromEnum::None
		);
	}

	/**
	 * チェッカーを優先度順に取得
	 *
	 * @return array<callable>
	 */
	private function getCheckers(): array {
		return [
			// Priority 1: メジャーSEOプラグイン
			fn( $postId ) => $this->checkAIOSEO( $postId ),
			fn( $postId ) => $this->checkYoastSEO( $postId ),

			// Priority 2: 国内向けSEOプラグイン
			fn( $postId ) => $this->checkSEOSimplePack( $postId ),

			// Priority 3: テーマ独自のOGP設定
			fn( $postId ) => $this->checkSWELL( $postId ),
			fn( $postId ) => $this->checkCocoon( $postId ),
		];
	}

	/**
	 * All in One SEO (AIOSEO) の画像設定をチェック
	 *
	 * AIOSEOの優先順位:
	 * 1. カスタムOGP画像
	 * 2. アイキャッチ画像（デフォルト設定時）
	 *
	 * @param int $postId
	 * @return ImageCheckResult|null 画像が設定されていればImageCheckResult、なければnull
	 */
	private function checkAIOSEO( int $postId ): ?ImageCheckResult {
		if ( ! class_exists( self::SEO_PLUGINS_CONFIG['aioseo']['class'] ) ) {
			return null;
		}

		$imageType = get_post_meta( $postId, self::AIOSEO_OG_IMAGE_TYPE, true );
		$customUrl = get_post_meta( $postId, self::AIOSEO_OG_IMAGE_URL, true );

		// カスタム画像が明示的に設定されている
		if ( 'custom' === $imageType && ! empty( $customUrl ) ) {
			return new ImageCheckResult(
				ImageCheckResultStatusEnum::OK,
				ImageSetFromEnum::AIOSEO
			);
		}

		// デフォルト設定（アイキャッチ使用）で、アイキャッチが設定されている
		// AIOSEOがアクティブな場合、アイキャッチもAIOSEO管理下として扱う
		if ( ( empty( $imageType ) || 'default' === $imageType ) && has_post_thumbnail( $postId ) ) {
			return new ImageCheckResult(
				ImageCheckResultStatusEnum::OK,
				ImageSetFromEnum::AIOSEO
			);
		}

		return null;
	}

	/**
	 * Yoast SEO の画像設定をチェック
	 *
	 * Yoast SEOの優先順位:
	 * 1. カスタムOGP画像
	 * 2. アイキャッチ画像（自動使用）
	 *
	 * @param int $postId
	 * @return ImageCheckResult|null 画像が設定されていればImageCheckResult、なければnull
	 */
	private function checkYoastSEO( int $postId ): ?ImageCheckResult {
		if ( ! class_exists( self::SEO_PLUGINS_CONFIG['yoast']['class'] ) ) {
			return null;
		}

		$customImage = get_post_meta( $postId, self::YOAST_OG_IMAGE, true );

		// カスタムOGP画像が明示的に設定されている
		if ( ! empty( $customImage ) ) {
			return new ImageCheckResult(
				ImageCheckResultStatusEnum::OK,
				ImageSetFromEnum::YoastSEO
			);
		}

		// Yoast SEOがアクティブな場合、アイキャッチを自動的にOGP画像として使用
		// そのため、アイキャッチがあればYoast SEO管理下として扱う
		if ( has_post_thumbnail( $postId ) ) {
			return new ImageCheckResult(
				ImageCheckResultStatusEnum::OK,
				ImageSetFromEnum::YoastSEO
			);
		}

		return null;
	}

	/**
	 * SEO SIMPLE PACK の画像設定をチェック
	 *
	 * @param int $postId
	 * @return ImageCheckResult|null 画像が設定されていればImageCheckResult、なければnull
	 */
	private function checkSEOSimplePack( int $postId ): ?ImageCheckResult {
		$imageUrl = get_post_meta( $postId, self::SSP_OG_IMAGE_URL, true );

		if ( ! empty( $imageUrl ) ) {
			return new ImageCheckResult(
				ImageCheckResultStatusEnum::OK,
				ImageSetFromEnum::SEOSimplePack
			);
		}

		return null;
	}

	/**
	 * SWELL テーマの画像設定をチェック
	 *
	 * SWELLの機能:
	 * - 投稿ごとにカスタムOGP画像を設定可能
	 * - メタキー: 'swell_ogp_img' (添付ファイルID)
	 *
	 * @param int $postId
	 * @return ImageCheckResult|null 画像が設定されていればImageCheckResult、なければnull
	 */
	private function checkSWELL( int $postId ): ?ImageCheckResult {
		if ( ! $this->isThemeActive( 'swell' ) ) {
			return null;
		}

		$ogpImageId = get_post_meta( $postId, self::SWELL_OGP_IMAGE, true );

		// SWELLのカスタムOGP画像が設定されている（添付ファイルIDで保存）
		if ( ! empty( $ogpImageId ) && is_numeric( $ogpImageId ) ) {
			// 添付ファイルが実際に存在するか確認
			if ( wp_get_attachment_url( $ogpImageId ) ) {
				return new ImageCheckResult(
					ImageCheckResultStatusEnum::OK,
					ImageSetFromEnum::SWELL
				);
			}
		}

		// SWELLがアクティブで、アイキャッチが設定されている場合
		// SWELLは独自のOGP出力を行うため、SWELL管理下として扱う
		if ( has_post_thumbnail( $postId ) ) {
			return new ImageCheckResult(
				ImageCheckResultStatusEnum::OK,
				ImageSetFromEnum::SWELL
			);
		}

		return null;
	}

	/**
	 * Cocoon テーマの画像設定をチェック
	 *
	 * Cocoonの機能:
	 * - 投稿ごとにカスタムOGP画像を設定可能
	 * - メタキー: 'og_image' (画像URL)
	 *
	 * @param int $postId
	 * @return ImageCheckResult|null 画像が設定されていればImageCheckResult、なければnull
	 */
	private function checkCocoon( int $postId ): ?ImageCheckResult {
		if ( ! $this->isThemeActive( 'cocoon' ) ) {
			return null;
		}

		$ogpImageUrl = get_post_meta( $postId, self::COCOON_OG_IMAGE, true );

		// CocoonのカスタムOGP画像が設定されている（URLで保存）
		if ( ! empty( $ogpImageUrl ) && filter_var( $ogpImageUrl, FILTER_VALIDATE_URL ) ) {
			return new ImageCheckResult(
				ImageCheckResultStatusEnum::OK,
				ImageSetFromEnum::Cocoon
			);
		}

		// Cocoonがアクティブで、アイキャッチが設定されている場合
		// Cocoonは独自のOGP出力を行うため、Cocoon管理下として扱う
		if ( has_post_thumbnail( $postId ) ) {
			return new ImageCheckResult(
				ImageCheckResultStatusEnum::OK,
				ImageSetFromEnum::Cocoon
			);
		}

		return null;
	}

	/**
	 * 指定されたテーマがアクティブかチェック
	 *
	 * @param string $themeKey SEO_PLUGINS_CONFIGのキー
	 * @return bool
	 */
	private function isThemeActive( string $themeKey ): bool {
		if ( ! isset( self::SEO_PLUGINS_CONFIG[ $themeKey ] ) ) {
			return false;
		}

		$config = self::SEO_PLUGINS_CONFIG[ $themeKey ];

		if ( 'theme' !== $config['type'] ) {
			return false;
		}

		// キャッシュがなければ取得
		if ( self::$activeTemplate === null ) {
			self::$activeTemplate = get_template();
		}

		// テーマスラッグの完全一致、または部分一致でチェック
		return self::$activeTemplate === $config['template']
		       || strpos( self::$activeTemplate, $config['template'] ) === 0;
	}

	/**
	 * 投稿保存時にステータスをチェック＆保存するメソッド
	 *
	 * 'save_post' フックで呼び出されます。
	 *
	 * @param int      $postId 保存された投稿のID
	 * @param \WP_Post $post   保存された投稿オブジェクト
	 * @param bool     $update 更新の場合はtrue
	 *
	 * @return void
	 */
	public function check_and_save_status_on_save( int $postId, \WP_Post $post, bool $update ): void
	{
// 自動保存やリビジョン、auto-draftは除外
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return;
		}
		if ( wp_is_post_revision( $postId ) || wp_is_post_autosave( $postId ) ) {
			return;
		}
		if ( 'auto-draft' === $post->post_status ) {
			return;
		}

		// チェック対象の投稿タイプか確認
		$allowedPostTypes = get_option( PixaliaConst::OPTION_POST_TYPES, [ 'post' ] );
		if ( ! in_array( $post->post_type, (array) $allowedPostTypes, true ) ) {
			return;
		}

		// 画像ステータスをチェック
		$result = $this->check( $postId );

		// ★ PostRepositoryに一括保存（これだけ！）
		$this->postRepository->saveImageCheckResult(
			$postId,
			$result,
			PixaliaConst::LOGIC_VERSION
		);
	}

	/**
	 * 投稿本文中に有効な画像が存在するかチェック
	 *
	 * チェック方法:
	 * 1. 高速チェック: `<img`文字列の存在確認
	 * 2. 詳細チェック: src属性を持つimgタグの存在確認
	 *
	 * @param int $postId 投稿ID
	 * @return bool 画像が存在すればtrue
	 */
	private function hasImageInContent( int $postId ): bool {
		$content = get_post_field( 'post_content', $postId );

		if ( empty( $content ) ) {
			return false;
		}

		// 高速チェック: <img タグの存在確認（大部分の投稿で早期リターン）
		if ( false === strpos( $content, '<img' ) ) {
			return false;
		}

		// より厳密なチェック: src属性を持つimgタグがあるか
		// （空のimgタグや壊れたマークアップを除外）
		return 1 === preg_match( '/<img[^>]+src=["\'][^"\']+["\'][^>]*>/i', $content );
	}

	/**
	 * PostRepositoryのゲッター（テスト用）
	 *
	 * @return PostRepository
	 */
	public function getPostRepository(): PostRepository {
		return $this->postRepository;
	}
}