<?php if ( !defined( 'ABSPATH' ) ) exit;//PHPの宣言と直接アクセスの拒否

/********** テーマファイルの変更ログ **********/
// 最終チェック時点のファイル状態を保存するキー (wp_options)
define('HAUP_FULL_STATE_OPTION_KEY', 'haup_last_changed_theme_files');
// 最終チェック時刻を保存するキー (wp_options)
define('HAUP_LAST_CHECK_TIME_KEY', 'haup_last_changed_theme_files_check_time');
define('HAUP_CHECK_INTERVAL', 3600); // 1時間=3600

/*** ログをグループ化して取得する汎用関数 (カスタムテーブル haup_change_theme_file_log から読み込み) ***/
function haup_get_grouped_change_logs($limit = 30) {
	global $wpdb;
	$table_name = $wpdb->prefix . 'haup_change_theme_file_log';

	// テーブルが存在しない場合は空配列を返す
	// phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter , WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching , WordPress.DB.PreparedSQL.InterpolatedNotPrepared
	if ($wpdb->get_var("SHOW TABLES LIKE '$table_name'") !== $table_name) {
		return array();
	}

	// 最初に、最新のロググループ（created_at）のユニークなタイムスタンプを取得
	// DISTINCT を使用して、ユニークな作成日時を降順で取得
	// phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter , WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching
	$timestamps = $wpdb->get_col(
		$wpdb->prepare(
			// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
			"SELECT DISTINCT created_at FROM $table_name ORDER BY created_at DESC LIMIT %d",
			$limit
		)
	);

	if (empty($timestamps)) {
		return array();
	}

	// 取得したタイムスタンプに基づいて、詳細なログデータを取得
	// IN句のプレースホルダーを動的に生成
	$placeholders = implode(',', array_fill(0, count($timestamps), '%s'));

	// phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter , WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching , PluginCheck.Security.DirectDB.UnescapedDBParameter
	$results = $wpdb->get_results(
		$wpdb->prepare(
			// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared , WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
			"SELECT log_type, log_filename, created_at FROM $table_name WHERE created_at IN ({$placeholders}) ORDER BY created_at DESC, id ASC",
			$timestamps
		)
	);

	$grouped_logs = array();

	// 取得した詳細データを created_at でグループ化
	foreach ($results as $row) {
		// created_atをキーとしてログをグループ化
		$group_key = $row->created_at;

		if (!isset($grouped_logs[$group_key])) {
				$grouped_logs[$group_key] = array(
					'timestamp' => $group_key,
					'changes' => array(
					'added' => array(),
					'changed' => array(),
					'deleted' => array(),
				),
			);
		}

		// log_type に応じてファイル名を格納
		switch ($row->log_type) {
			case 'added':
				$grouped_logs[$group_key]['changes']['added'][] = $row->log_filename;
				break;
			case 'changed':
				$grouped_logs[$group_key]['changes']['changed'][] = $row->log_filename;
				break;
			case 'deleted':
				$grouped_logs[$group_key]['changes']['deleted'][] = $row->log_filename;
				break;
		}
	}

	// 連想配列の値を返す (キーは created_at でソート済み)
	return array_values($grouped_logs);
}

/*** テーマディレクトリ全体を再帰的にスキャンし、ファイルの状態を取得するヘルパー関数 ***/
function haup_get_theme_directory_state($dir_path) {
	$state = array();

	$ignore_list = array(//変更ログから除外する拡張子・ディレクトリ・個別ファイルの指定
		'*.log', '*.txt', '*.md', '*.pot',
		'*.png','*.jpg', '*.jpeg', '*.gif', '*.svg', '*.webp', '*.ico',
		'*.woff', '*.woff2', '*.ttf', '*.eot', '*.otf',
		'assets/',
		'languages/',
		'theme.json',
		'styles/',
		'templates/',
		'parts/',
		'patterns/',
		'overwrite-theme-json/',
		'node_modules/',
		'screenshot.png',
		'readme.txt',
	);

	if (!is_dir($dir_path)) {
		return $state;
	}

	$base_path = trailingslashit($dir_path);

	try {
		$iterator = new RecursiveIteratorIterator(
			new RecursiveDirectoryIterator($dir_path, RecursiveDirectoryIterator::SKIP_DOTS),
			RecursiveIteratorIterator::SELF_FIRST
		);

		foreach ($iterator as $file) {
			if ($file->isFile()) {
				$relative_path = str_replace($base_path, '' , $file->getPathname());

				$skip = false;

				foreach ($ignore_list as $pattern) {
					if (fnmatch($pattern, $relative_path)) {
						$skip = true;
						break;
					}
				}

				if (!$skip) {
					$state[$relative_path] = filemtime($file->getPathname());
				}
			}
		}
	} catch (UnexpectedValueException $e) {
		return $state;
	}

	return $state;
}

/*** テーマディレクトリ全体の変更をチェックし、ログをカスタムテーブルに保存する ***/
function haup_theme_directory_change_monitor_check() {
	global $wpdb;
	$table_name = $wpdb->prefix . 'haup_change_theme_file_log';

	$template_dir = get_template_directory();// 親テーマのパス
	$stylesheet_dir = get_stylesheet_directory();// 子テーマのパス
	$is_child_theme = ($template_dir !== $stylesheet_dir);

	$current_state = array();

	$current_theme_text = __('File location: [currently active theme]/','hima-art-utility');
	$parent_theme_text = __('File location: [parent theme (parent theme if child theme is enabled)]/','hima-art-utility');

	// 1. アクティブテーマ (子テーマ/単一テーマ) のファイル状態を取得
	$child_theme_state = haup_get_theme_directory_state($stylesheet_dir);

	foreach ($child_theme_state as $path => $time) {
		$current_state[ $current_theme_text . $path] = $time;
	}

	// 2. 親テーマのファイル状態を取得（子テーマ使用時のみ）
	if ($is_child_theme) {
		$parent_theme_state = haup_get_theme_directory_state($template_dir);

		foreach ($parent_theme_state as $path => $time) {
			$current_state[ $parent_theme_text . $path] = $time;
		}
	}

	// 前回の状態をoptionsテーブルから取得
	$previous_state = get_option(HAUP_FULL_STATE_OPTION_KEY, array());

	// --- 初回実行時の処理（初回ノイズを排除） ---
	// 前回の状態が空の場合、ログには記録せず、現在の状態を保存して終了する
	if (empty($previous_state)) {
		update_option(HAUP_FULL_STATE_OPTION_KEY, $current_state);
		return;
	}

	// --- 2回目以降の実行時の処理 ---

	// 変更、追加、削除されたファイルを検出
	$changed = array_diff_assoc($current_state, $previous_state);
	$deleted = array_diff_key($previous_state, $current_state);
	$added = array_diff_key($current_state, $previous_state);

	if (!empty($changed) || !empty($deleted) || !empty($added)) {


		// ログ挿入時刻を統一するため、一度取得
		$current_log_time = current_time('mysql');

		// 変更されたファイルを個別にログに記録
		$log_map = array(
			'added' => $added,
			'changed' => $changed,
			'deleted' => $deleted
		);
        
		foreach ($log_map as $type => $files) {
			foreach (array_keys($files) as $filename) {
				// カスタムテーブルにログを挿入 (1ファイル = 1行)
				// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
				$wpdb->insert(
					$table_name,
					array(
						'log_type' => $type,// 変更タイプ (added, changed, deleted)
						'log_filename' => $filename, // ファイルのフルパス（相対テーマパス）
						'created_at' => $current_log_time,
						// 'log_entry' => "--- {$type}: {$filename} ---",//旧ログの列（使用していないが一応残す）
					),
					// ⚠️ 注意: log_entry カラムを残すため、フォーマット指定子は4つ ('%s', '%s', '%s', '%s') のままにする
					array('%s', '%s', '%s', '%s') 
				);
			}
		}

		// 最終状態を更新 (optionsテーブル)
		update_option(HAUP_FULL_STATE_OPTION_KEY, $current_state);
	}
}

/*** 管理画面アクセス時の実行制御 ***/
// (変更なし - 読みやすさのために省略)
function haup_theme_monitor_on_admin_load() {
	// テーブルが存在しない場合はチェックを行わない
	global $wpdb;
	$table_name = $wpdb->prefix . 'haup_change_theme_file_log';
	// phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter , WordPress.DB.DirectDatabaseQuery.DirectQuery , WordPress.DB.DirectDatabaseQuery.NoCaching , WordPress.DB.PreparedSQL.InterpolatedNotPrepared
	if ($wpdb->get_var("SHOW TABLES LIKE '$table_name'") !== $table_name) {
		return;
	}

	if (current_user_can('manage_options') && is_admin()) {
		$last_check = get_option(HAUP_LAST_CHECK_TIME_KEY, 0);

		if (time() > $last_check + HAUP_CHECK_INTERVAL) {
			haup_theme_directory_change_monitor_check();
			update_option(HAUP_LAST_CHECK_TIME_KEY, time());
		}
	}
}
add_action('admin_init', 'haup_theme_monitor_on_admin_load');

/***** 管理画面でのログ表示機能 *****/
/*** ログを表示するための管理メニューを追加する ***/
// (変更なし)
function haup_add_admin_menu_theme_file_change_log() {
	add_submenu_page(
		'haumenu-admin-page',
		'Theme File Change Log',
		__('Theme Changelog','hima-art-utility'),
		'manage_options',
		'haup-theme-file-change-log',
		'haup_log_page_content_full'
	);
}
add_action('admin_menu', 'haup_add_admin_menu_theme_file_change_log');

/*** テーマファイル変更ログをすべて削除する処理 ***/
function haup_delete_all_change_logs() {
	global $wpdb;
	$table_name = $wpdb->prefix . 'haup_change_theme_file_log';

	// ユーザー権限の確認
	if (!current_user_can('manage_options')) {
		$unauthorized_text = __('Unauthorized','hima-art-utility');
		wp_die( esc_html( $unauthorized_text ) );
	}

	// ノンス（Nonce）の確認
	if (!isset($_POST['_wpnonce']) || !wp_verify_nonce($_POST['_wpnonce'], 'haup_delete_logs')) {
		$scheck_text = __('Security check failed','hima-art-utility');
		wp_die( esc_html( $scheck_text ) );
	}

	// ログテーブルが存在するか確認
	// phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter , WordPress.DB.PreparedSQL.InterpolatedNotPrepared
	if ($wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name) {
		// テーブル内の全レコードを削除
		// phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter , WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$result = $wpdb->query("TRUNCATE TABLE {$table_name}");
        
		if ($result !== false) {
			$message = __('Removed all theme file change logs','hima-art-utility');
		} else {
			$message = __('An error occurred while deleting the log','hima-art-utility');
		}
	} else {
		$message = __('The log table did not exist','hima-art-utility');
	}

	// ログ画面にリダイレクトし、結果メッセージを表示
	wp_safe_redirect(
		add_query_arg(
			array('page' => 'haup-theme-file-change-log', 'log_message' => urlencode($message)),
			admin_url('admin.php')
		)
	);

	exit;
}
// 管理画面初期化時に削除処理をフック
add_action('admin_init', function() {
	if (isset($_POST['haup_delete_logs']) && current_user_can('manage_options')) {
		haup_delete_all_change_logs();
	}
});

/*** 全ログ画面の表示内容 ***/
function haup_log_page_content_full() {
	if (!current_user_can('manage_options')) {
		return;
	}

	// 変更: haup_get_grouped_change_logs を使用 (ロググループ30件を取得)
	$log_groups = haup_get_grouped_change_logs(30);
	$last_check_time = get_option(HAUP_LAST_CHECK_TIME_KEY, 0);
	
	// ログタイプの日本語訳
	$type_labels = array(
		'added'   => __('[Addition]','hima-art-utility'),
		'changed' => __('[Modification]','hima-art-utility'),
		'deleted' => __('[Deletion]','hima-art-utility'),
	);

	//ページ内の文字列
	$page_title = __('File change log in theme directory','hima-art-utility');
	$page_description = __('Changes in files within the active theme (both parent and child themes when using a child theme) are detected every hour and displayed as a list. Frequently updated files (images, fonts, theme setting JSON, etc.) are excluded, but changes to these files may be displayed in some cases, such as theme updates or automatic file rebuild processes.','hima-art-utility');
	$page_description2 = __('*Please check the plugin settings screen for details on the operation of this function and the files and folders excluded from the log.','hima-art-utility');
	$log_delete_title = __('Delete logs','hima-art-utility');
	$log_delete_description = __('If you no longer need the logs, you can delete all change logs. This action cannot be undone.','hima-art-utility');
	$log_delete_confirm = __('Are you sure you want to delete all log data? This action cannot be undone.','hima-art-utility');
	$log_delete_button_title = __('Delete all logs','hima-art-utility');
	$check_time_title = __('File check date and time','hima-art-utility');
	$last_check_time_title = __('Last check date and time','hima-art-utility');
	$no_checked_message = __('Unchecked','hima-art-utility');
	$log_title = __('Changelog (Latest 30)','hima-art-utility');
	$log_table_title01 = __('Date and time of change','hima-art-utility');
	$log_table_title02 = __('Modified files','hima-art-utility');
	$no_log_message = __('There is currently no changelog in the theme directory','hima-art-utility');

?>
<div class="wrap">
	<h1><?php echo esc_html( $page_title ); ?></h1>

	<?php 
	// 削除処理後のメッセージを表示
	if (isset($_GET['log_message'])) :
	?>
		<div class="updated notice is-dismissible">
			<p><strong><?php echo esc_html(urldecode($_GET['log_message'])); ?></strong></p>
		</div>
	<?php endif; ?>

	<p><?php echo esc_html( $page_description ); ?></p>
	<p><?php echo esc_html( $page_description2 ); ?></p>
	<hr>
    
	<h2><?php echo esc_html( $log_delete_title ); ?></h2>
	<div style="margin-bottom: 20px;">
		<p><?php echo esc_html( $log_delete_description ); ?></p>
		<form method="post" onsubmit="return confirm( <?php echo esc_html( $log_delete_confirm ); ?>);">
			<?php wp_nonce_field('haup_delete_logs'); ?>
			<input type="hidden" name="haup_delete_logs" value="1">
			<input type="submit" class="button button-secondary" value="<?php echo esc_html( $log_delete_button_title ); ?>">
		</form>
	</div>
	<hr>

	<h2><?php echo esc_html( $check_time_title ); ?></h2>
	<table class="wp-list-table widefat fixed striped" style="max-width: 600px;">
		<tbody>
			<tr>
				<th style="width: 250px;"><?php echo esc_html( $last_check_time_title ); ?></th>
				<td><?php echo $last_check_time ? esc_html(wp_date('Y-m-d H:i:s T', $last_check_time)) : esc_html( $no_checked_message ); ?></td>
			</tr>
		</tbody>
	</table>
	
	<h2><?php echo esc_html( $log_title ); ?></h2>
	<?php if (!empty($log_groups)) : ?>
		<table class="wp-list-table widefat fixed striped">
			<thead>
				<tr>
					<th style="font-weight: bold; width: 200px;"><?php echo esc_html( $log_table_title01 ); ?></th>
					<th style="font-weight: bold;"><?php echo esc_html( $log_table_title02 ); ?></th>
				</tr>
			</thead>
			<tbody>
				<?php foreach ($log_groups as $group) : ?>
					<tr>
						<td>
							<strong><?php echo esc_html($group['timestamp']); ?></strong>
						</td>
						<td>
							<pre style="white-space: pre-wrap; margin: 0; padding: 0; border: none; background: none;">
<?php //この宣言前にタブなどがあると1行目の左に空白ができるのでそのままにすること
								$output = '';
								// ログタイプごとにファイル名を表示
								foreach ($type_labels as $type => $label) {
									// ファイルリストが空でない場合のみ出力
									if (!empty($group['changes'][$type])) {
										// ファイルリストをループし、ファイルごとに [タイプ]: ファイルパス の形式で改行付きで結合
										foreach ($group['changes'][$type] as $filename) {
											$output .= $label . ": " . $filename . "\n";
										}
									}
								}
								// 最後の改行を削除して出力
								echo esc_html(trim($output));
?>
							</pre>
						</td>
					</tr>
				<?php endforeach; ?>
			</tbody>
		</table>
	<?php else : ?>
		<p><?php echo esc_html( $no_log_message ); ?></p>
	<?php endif; ?>
</div>
<?php
}

/***** ダッシュボードウィジェット機能 *****/
/*** ダッシュボードウィジェットの登録 ***/
function haup_add_theme_change_log_dashboard_widget() {
	wp_add_dashboard_widget(
		'haup_theme_change_log_widget', 
		__('Theme file change log (Latest 5)','hima-art-utility'), 
		'haup_theme_change_log_dashboard_widget_content'
	);
}
add_action('wp_dashboard_setup', 'haup_add_theme_change_log_dashboard_widget');


/*** ダッシュボードウィジェットのコンテンツ ***/
function haup_theme_change_log_dashboard_widget_content() {
	// 変更: haup_get_grouped_change_logs() を使用 (ロググループ5件を取得)
	$log_groups = haup_get_grouped_change_logs(5);

	// ログタイプの日本語訳 (ウィジェット用略称)
	$type_labels = array(
		'added' => __('[Addition]','hima-art-utility'), // Added
		'changed' => __('[Modification]','hima-art-utility'), // Changed
		'deleted' => __('[Deletion]','hima-art-utility'), // Deleted
	);
	
	//メッセージ
	$nolog_message = __('There is currently no changelog in the theme directory','hima-art-utility');
	$logpage_link_title = __('View the full changelog','hima-art-utility');

	echo '<div style="max-height: 250px; overflow-y: auto; border: 1px solid #ddd; padding: 5px; background: #fff;">';
	if (empty($log_groups)) {
		echo '<p>'.esc_html( $nolog_message ).'</p>';
	} else {
		echo '<ul style="list-style-type: none; margin: 0; padding: 0;">';

		foreach ($log_groups as $group) {
			
			$summary = array();
			// 変更サマリーを生成
			foreach ($type_labels as $type => $label) {
				$count = count($group['changes'][$type]);
				if ($count > 0) {
					$summary[] = $label . ':' . $count;
				}
			}
			$summary_text = implode(' | ', $summary);

			echo '<li style="margin-bottom: 10px; border-bottom: 1px dashed #eee; padding-bottom: 5px;">';
			
			// 変更日時とサマリーを表示
			echo '<strong>' . esc_html($group['timestamp']) . '</strong> ';
			echo '<span style="color: #666; font-size: 10px;">(' . esc_html($summary_text) . ')</span>';
			
			// 詳細な変更ファイルリストを表示
			echo '<pre style="white-space: pre-wrap; margin: 5px 0 0 10px; padding: 0; font-size: 11px; line-height: 1.3;">';
			$output = '';
			foreach ($type_labels as $type => $label) {
				// ファイルリストが空でない場合のみ出力
				if (!empty($group['changes'][$type])) {
					// ファイルリストをループし、ファイルごとに [タイプ]: ファイルパス の形式で改行付きで結合
					foreach ($group['changes'][$type] as $filename) {
						$output .= $label . ": " . $filename . "\n";
					}
				}
			}
			echo esc_html(trim($output));
			echo '</pre>';
			
			echo '</li>';
		}

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

	// 全ログ画面へのリンク
	$log_page_url = admin_url('admin.php?page=haup-theme-file-change-log');
	echo '<p style="text-align: right; margin-top: 10px;">';
	echo '<a href="' . esc_url($log_page_url) . '" class="haup-dashboard-widget-button">'.esc_html( $logpage_link_title ).'</a>';
	echo '</p>';
}