<?php
/**
 * Plugin Name: SEO Console by Sun Reaches
 * Plugin URI:  https://sunreaches.com/seo-console
 * Description: All-in-one SEO command center — Google Search Console, Bing Webmaster, GA4 & PageSpeed Insights, automatic analysis & alerts, KPI tracking with monthly snapshots, keyword mapping, on-page checklist, content drafting & approval workflow, mini CRM and reporting. Free tier included; upgrade to Pro for KPI/content/CRM/reporting modules. English & Vietnamese interface (switch in Settings). Trung tâm điều hành SEO trọn gói bằng Tiếng Việt/English, có bản Free và Pro.
 * Version:     1.0.0
 * Requires at least: 6.0
 * Requires PHP: 7.4
 * Author:      Sun Reaches
 * Author URI:  https://sunreaches.com
 * Text Domain: seo-console
 * Domain Path: /languages
 * License:     GPLv2 or later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 *
 * Copyright (c) Sun Reaches (https://sunreaches.com). All rights reserved.
 * This program is free software distributed under the GPLv2 (or later) license.
 */

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

define( 'TTSEO_VER', '1.0.0' );
define( 'TTSEO_CACHE_TTL', 6 * HOUR_IN_SECONDS );

define( 'TTSEO_URL', plugin_dir_url( __FILE__ ) );

// Freemius SDK phải nạp ĐẦU TIÊN (khuyến nghị chính thức của Freemius — trước
// mọi include/hook khác của plugin).
require_once __DIR__ . '/freemius.php';

// Ngôn ngữ + quyền hạn + freemium phải nạp TRƯỚC các module (dùng ttseo_t()/ttseo_access()/ttseo_is_pro() ngay khi include).
require_once __DIR__ . '/languages.php';
require_once __DIR__ . '/roles.php';
require_once __DIR__ . '/licensing.php';

require_once __DIR__ . '/workflow.php';
require_once __DIR__ . '/articles.php';
require_once __DIR__ . '/kpi-report.php';
require_once __DIR__ . '/content-keywords.php';
require_once __DIR__ . '/crm.php';
require_once __DIR__ . '/strategy.php';
require_once __DIR__ . '/onpage.php';
require_once __DIR__ . '/report.php';
require_once __DIR__ . '/engagement.php';
require_once __DIR__ . '/users.php';

// Bản dịch cộng đồng (nếu site tự thêm .mo cho text domain 'seo-console').
add_action( 'plugins_loaded', function () {
	load_plugin_textdomain( 'seo-console', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
} );

// An toàn cho site đang nâng cấp từ bản cũ (không qua activation hook): tạo vai trò nếu thiếu.
add_action( 'admin_init', function () {
	if ( ! get_role( TTSEO_ROLE ) ) {
		ttseo_roles_install();
	}
} );

/* =========================================================================
 * OPTIONS
 * ========================================================================= */
function ttseo_opt( $key, $default = '' ) {
	$o = get_option( 'ttseo_settings', array() );
	return isset( $o[ $key ] ) ? $o[ $key ] : $default;
}

/* =========================================================================
 * MODULE MANAGER — bật/tắt từng phân hệ (cấu hình trong plugin)
 * ========================================================================= */
function ttseo_modules_registry() {
	$free = ttseo_t( ' (Free)', ' (Free)' );
	$pro  = ttseo_t( ' (Pro)', ' (Pro)' );
	return array(
		'analytics' => array( ttseo_t( 'Tổng quan & Phân tích', 'Overview & Analysis' ) . $free, ttseo_t( 'GSC/Bing/GA4/PageSpeed + cảnh báo SEO', 'GSC/Bing/GA4/PageSpeed + automatic SEO alerts' ), 'ttseo-dashboard' ),
		'kpi'       => array( ttseo_t( 'KPI & Tiến độ', 'KPI & Progress' ) . $pro, ttseo_t( 'Baseline B/C/R + 20 từ khóa KPI', 'Baseline B/C/R + 20 KPI keywords' ), 'ttseo-kpi' ),
		'work'      => array( ttseo_t( 'Công việc SEO', 'SEO Work' ) . $free, ttseo_t( 'On-page Checklist (chấm 11 tiêu chí, trước/sau) + Indexation, Authority, Action log', 'On-page checklist (11 criteria, before/after) + Indexation, Authority, Action log' ), 'ttseo-work' ),
		'articles'  => array( ttseo_t( 'Soạn & Duyệt bài SEO', 'SEO Content & Approval' ) . $pro, ttseo_t( 'Viết bài, xem trước như trên site live, duyệt (tự xuất bản), đếm ngược hạn duyệt, ma trận từ khóa KPI', 'Draft content, live-style preview, approve (auto-publish), approval countdown, KPI keyword matrix' ), 'ttseo-articles' ),
		'content'   => array( ttseo_t( 'GĐ1: Base & Nội dung', 'Phase 1: Baseline & Content' ) . $pro, ttseo_t( 'Điểm SEO từng bài, baseline giai đoạn 1', 'Per-post SEO score, phase-1 baseline' ), 'ttseo-content' ),
		'keywords'  => array( ttseo_t( 'Chiến lược từ khóa', 'Keyword Strategy' ) . $pro, ttseo_t( 'Nghiên cứu & phân tích + Keyword Mapping (gán từ khóa↔URL, topic cluster) — 2 tab cùng trang', 'Research & analysis + Keyword Mapping (keyword↔URL, topic clusters) — 2 tabs, 1 page' ), 'ttseo-keywords' ),
		'crm'       => array( ttseo_t( 'Lead & CRM', 'Leads & CRM' ) . $pro, ttseo_t( 'Thu thập & đánh giá lead, attribution', 'Lead capture & scoring, attribution' ), 'ttseo-crm' ),
		'report'    => array( ttseo_t( 'Báo cáo & Review', 'Reports & Review' ) . $pro, ttseo_t( 'Báo cáo tháng, biên bản họp', 'Monthly reports, meeting notes' ), 'ttseo-report' ),
		'users'     => array( ttseo_t( 'Người dùng & Phân quyền', 'Users & Permissions' ) . $free, ttseo_t( 'Tạo tài khoản SEO Dashboard riêng, đổi mật khẩu, đổi vai trò, cấp quyền duyệt bài SEO', 'Create dedicated SEO Dashboard accounts, change passwords/roles, grant SEO content approval rights' ), 'ttseo-users' ),
	);
}
/** Mặc định: tất cả bật. */
function ttseo_module_on( $slug ) {
	$m = get_option( 'ttseo_modules' );
	if ( ! is_array( $m ) ) {
		return true; // chưa cấu hình → bật hết
	}
	return ! empty( $m[ $slug ] );
}

// Link nhanh trên trang Plugins: Bảng điều khiển · Cấu hình
add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), function ( $links ) {
	$mine = array(
		'<a href="' . esc_url( admin_url( 'admin.php?page=ttseo-dashboard' ) ) . '">' . esc_html( ttseo_t( 'Bảng điều khiển', 'Dashboard' ) ) . '</a>',
		'<a href="' . esc_url( admin_url( 'admin.php?page=ttseo-settings' ) ) . '"><b>' . esc_html( ttseo_t( 'Cấu hình', 'Settings' ) ) . '</b></a>',
	);
	if ( ! ttseo_is_pro() ) {
		$mine[] = '<a href="https://sunreaches.com/seo-console/pricing" target="_blank" rel="noopener" style="color:#8a3ffc;font-weight:600;">' . esc_html( ttseo_t( 'Nâng cấp Pro', 'Upgrade to Pro' ) ) . '</a>';
	}
	return array_merge( $mine, $links );
} );
add_filter( 'plugin_row_meta', function ( $links, $file ) {
	if ( plugin_basename( __FILE__ ) === $file ) {
		$links[] = esc_html( ttseo_t( 'Phiên bản', 'Version' ) ) . ' ' . TTSEO_VER . ' · SEO Console by Sun Reaches';
		$links[] = '<a href="https://sunreaches.com" target="_blank" rel="noopener">sunreaches.com</a>';
	}
	return $links;
}, 10, 2 );

// Vô hiệu hóa: gỡ cron để tránh cron mồ côi
register_deactivation_hook( __FILE__, function () {
	$ts = wp_next_scheduled( 'ttseo_kpi_snapshot_cron' );
	if ( $ts ) {
		wp_unschedule_event( $ts, 'ttseo_kpi_snapshot_cron' );
	}
} );

// Kích hoạt: tạo bảng + vai trò "SEO Dashboard User" ngay
register_activation_hook( __FILE__, function () {
	foreach ( array( 'ttseo_roles_install', 'ttseo_wf_install', 'ttseo_crm_install', 'ttseo_kw_install', 'ttseo_op_install', 'ttseo_kpi_snap_install', 'ttseo_eng_install' ) as $fn ) {
		if ( function_exists( $fn ) ) {
			$fn();
		}
	}
} );

/* =========================================================================
 * ADMIN MENU
 * ========================================================================= */
add_action( 'admin_menu', function () {
	add_menu_page( 'SEO Dashboard', 'SEO Dashboard', 'ttseo_access', 'ttseo-dashboard', 'ttseo_render_dashboard', 'dashicons-chart-area', 3 );
	add_submenu_page( 'ttseo-dashboard', ttseo_t( 'Tổng quan', 'Overview' ), ttseo_t( 'Tổng quan', 'Overview' ), 'ttseo_access', 'ttseo-dashboard', 'ttseo_render_dashboard' );
	// Cài đặt kết nối chứa API key/secret — chỉ Administrator (manage_options) mới được vào, kể cả user có quyền ttseo_access.
	add_submenu_page( 'ttseo-dashboard', ttseo_t( 'Cài đặt kết nối', 'Connection Settings' ), ttseo_t( 'Cài đặt kết nối', 'Connection Settings' ), 'manage_options', 'ttseo-settings', 'ttseo_render_settings' );
} );

/* =========================================================================
 * SETTINGS SAVE / REFRESH
 * ========================================================================= */
add_action( 'admin_init', function () {
	if ( ! isset( $_POST['ttseo_save'] ) || ! current_user_can( 'manage_options' ) || ! ttseo_is_unlocked() ) {
		return;
	}
	check_admin_referer( 'ttseo_settings_save' );
	update_option( 'ttseo_settings', array(
		'gsc_property'    => sanitize_text_field( wp_unslash( $_POST['gsc_property'] ?? '' ) ),
		'gsc_sa_json'     => trim( (string) wp_unslash( $_POST['gsc_sa_json'] ?? '' ) ),
		'bing_apikey'     => sanitize_text_field( wp_unslash( $_POST['bing_apikey'] ?? '' ) ),
		'bing_siteurl'    => esc_url_raw( wp_unslash( $_POST['bing_siteurl'] ?? '' ) ),
		'ga4_property_id' => preg_replace( '/\D/', '', (string) wp_unslash( $_POST['ga4_property_id'] ?? '' ) ),
		'psi_apikey'      => sanitize_text_field( wp_unslash( $_POST['psi_apikey'] ?? '' ) ),
		'client_emails'   => sanitize_textarea_field( wp_unslash( $_POST['client_emails'] ?? '' ) ),
		'notify_email'    => sanitize_text_field( wp_unslash( $_POST['notify_email'] ?? '' ) ),
		'ui_lang'         => 'en' === ( $_POST['ui_lang'] ?? '' ) ? 'en' : 'vi',
	) );
	// Bật/tắt module
	if ( isset( $_POST['ttseo_modules_form'] ) ) {
		$mods = array();
		foreach ( array_keys( ttseo_modules_registry() ) as $slug ) {
			$mods[ $slug ] = ! empty( $_POST['module'][ $slug ] ) ? 1 : 0;
		}
		update_option( 'ttseo_modules', $mods );
	}
	// Đổi / xóa mật khẩu bảo vệ
	$new_pass = (string) wp_unslash( $_POST['ttseo_new_pass'] ?? '' );
	if ( 'REMOVE' === $new_pass ) {
		delete_option( 'ttseo_view_pass_hash' );
	} elseif ( '' !== trim( $new_pass ) ) {
		update_option( 'ttseo_view_pass_hash', password_hash( $new_pass, PASSWORD_DEFAULT ) );
	}
	ttseo_flush_cache();
	add_action( 'admin_notices', function () {
		echo '<div class="notice notice-success is-dismissible"><p>' . esc_html( ttseo_t( 'Đã lưu cài đặt và xóa cache.', 'Settings saved and cache cleared.' ) ) . '</p></div>';
	} );
} );

add_action( 'admin_init', function () {
	if ( isset( $_GET['ttseo_refresh'] ) && ttseo_access() && ttseo_is_unlocked() && check_admin_referer( 'ttseo_refresh' ) ) {
		ttseo_flush_cache();
		wp_safe_redirect( admin_url( 'admin.php?page=ttseo-dashboard&refreshed=1' ) );
		exit;
	}
} );

function ttseo_flush_cache() {
	global $wpdb;
	$wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '\_transient\_ttseo\_%' OR option_name LIKE '\_transient\_timeout\_ttseo\_%'" );
}

/* =========================================================================
 * CỔNG MẬT KHẨU RIÊNG — khóa Dashboard + Settings bằng 1 mật khẩu độc lập
 * (nằm trên lớp đăng nhập admin; hash lưu trong option, mở khóa bằng cookie HMAC)
 * ========================================================================= */
define( 'TTSEO_GATE_COOKIE', 'ttseo_gate' );

function ttseo_gate_enabled() {
	return (bool) get_option( 'ttseo_view_pass_hash', '' );
}
function ttseo_gate_token() {
	$hash = get_option( 'ttseo_view_pass_hash', '' );
	return hash_hmac( 'sha256', 'ttseo-gate|' . get_current_user_id(), $hash . wp_salt( 'auth' ) );
}
function ttseo_is_unlocked() {
	if ( ! ttseo_gate_enabled() ) {
		return true; // chưa đặt mật khẩu → mở (chỉ còn lớp admin)
	}
	return isset( $_COOKIE[ TTSEO_GATE_COOKIE ] ) && hash_equals( ttseo_gate_token(), (string) $_COOKIE[ TTSEO_GATE_COOKIE ] );
}
function ttseo_set_gate_cookie() {
	setcookie( TTSEO_GATE_COOKIE, ttseo_gate_token(), array(
		'expires'  => time() + 7 * DAY_IN_SECONDS,
		'path'     => '/wp-admin',
		'secure'   => is_ssl(),
		'httponly' => true,
		'samesite' => 'Lax',
	) );
}
function ttseo_clear_gate_cookie() {
	setcookie( TTSEO_GATE_COOKIE, '', array( 'expires' => time() - 3600, 'path' => '/wp-admin', 'secure' => is_ssl(), 'httponly' => true, 'samesite' => 'Lax' ) );
}

// Xử lý mở khóa / khóa lại — chạy sớm (trước khi xuất HTML) để set cookie được.
add_action( 'admin_init', function () {
	if ( ! ttseo_access() ) {
		return;
	}
	$page = sanitize_key( $_GET['page'] ?? '' );
	// Mọi trang của phân hệ đều dùng chung cổng mật khẩu
	$is_ours = 0 === strpos( $page, 'ttseo-' );

	if ( isset( $_POST['ttseo_unlock'] ) && $is_ours ) {
		check_admin_referer( 'ttseo_unlock' );
		$pw   = (string) wp_unslash( $_POST['ttseo_pw'] ?? '' );
		$hash = get_option( 'ttseo_view_pass_hash', '' );
		if ( $hash && password_verify( $pw, $hash ) ) {
			ttseo_set_gate_cookie();
			wp_safe_redirect( admin_url( 'admin.php?page=' . $page ) );
			exit;
		}
		wp_safe_redirect( admin_url( 'admin.php?page=' . $page . '&gate=fail' ) );
		exit;
	}

	if ( isset( $_GET['ttseo_lock'] ) && $is_ours ) {
		ttseo_clear_gate_cookie();
		wp_safe_redirect( admin_url( 'admin.php?page=' . $page . '&locked=1' ) );
		exit;
	}
} );

// Form nhập mật khẩu
function ttseo_render_gate() {
	$fail = isset( $_GET['gate'] ) && 'fail' === $_GET['gate'];
	echo '<div class="wrap"><h1>🔒 SEO Dashboard — ' . esc_html( ttseo_t( 'Khu vực bảo mật', 'Protected area' ) ) . '</h1>';
	echo '<div style="max-width:420px;margin-top:18px;background:#fff;border:1px solid #dcdfe3;border-top:3px solid #1f5c93;border-radius:8px;padding:22px 24px;">';
	echo '<p style="margin-top:0;color:#50575e;">' . esc_html( ttseo_t( 'Trang này được bảo vệ bằng mật khẩu riêng. Nhập mật khẩu để xem.', 'This page is protected by a separate password. Enter it to continue.' ) ) . '</p>';
	if ( $fail ) {
		echo '<div class="notice notice-error inline" style="margin:0 0 12px;"><p>' . esc_html( ttseo_t( 'Sai mật khẩu. Thử lại.', 'Wrong password. Try again.' ) ) . '</p></div>';
	}
	echo '<form method="post"><input type="hidden" name="ttseo_unlock" value="1">';
	wp_nonce_field( 'ttseo_unlock' );
	echo '<input type="password" name="ttseo_pw" class="regular-text" style="width:100%;margin-bottom:12px;" placeholder="' . esc_attr( ttseo_t( 'Mật khẩu', 'Password' ) ) . '" autofocus autocomplete="current-password">';
	echo '<button type="submit" class="button button-primary button-large" style="width:100%;">' . esc_html( ttseo_t( 'Mở khóa', 'Unlock' ) ) . '</button>';
	echo '</form></div></div>';
}

/* =========================================================================
 * GOOGLE OAUTH (Service Account JWT → token), theo scope
 * ========================================================================= */
function ttseo_google_token( $scope ) {
	$json = ttseo_opt( 'gsc_sa_json' );
	if ( ! $json ) {
		return new WP_Error( 'no_sa', ttseo_t( 'Chưa cấu hình Service Account JSON.', 'Service Account JSON not configured.' ) );
	}
	$creds = json_decode( $json, true );
	if ( ! $creds || empty( $creds['client_email'] ) || empty( $creds['private_key'] ) ) {
		return new WP_Error( 'bad_sa', ttseo_t( 'Service Account JSON không hợp lệ.', 'Invalid Service Account JSON.' ) );
	}
	$cache_key = 'ttseo_gtok_' . md5( $scope . $creds['client_email'] );
	$cached    = get_transient( $cache_key );
	if ( $cached ) {
		return $cached;
	}
	$now    = time();
	$header = ttseo_b64url( wp_json_encode( array( 'alg' => 'RS256', 'typ' => 'JWT' ) ) );
	$claim  = ttseo_b64url( wp_json_encode( array(
		'iss'   => $creds['client_email'],
		'scope' => $scope,
		'aud'   => 'https://oauth2.googleapis.com/token',
		'exp'   => $now + 3600,
		'iat'   => $now,
	) ) );
	$signing_input = $header . '.' . $claim;
	$signature     = '';
	if ( ! openssl_sign( $signing_input, $signature, $creds['private_key'], 'SHA256' ) ) {
		return new WP_Error( 'sign_fail', ttseo_t( 'Không ký được JWT.', 'Could not sign the JWT.' ) );
	}
	$jwt  = $signing_input . '.' . ttseo_b64url( $signature );
	$resp = wp_remote_post( 'https://oauth2.googleapis.com/token', array(
		'timeout' => 15,
		'body'    => array( 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion' => $jwt ),
	) );
	if ( is_wp_error( $resp ) ) {
		return $resp;
	}
	$data = json_decode( wp_remote_retrieve_body( $resp ), true );
	if ( empty( $data['access_token'] ) ) {
		return new WP_Error( 'token_fail', ttseo_t( 'Lấy access_token thất bại: ', 'Failed to obtain access_token: ' ) . esc_html( wp_remote_retrieve_body( $resp ) ) );
	}
	set_transient( $cache_key, $data['access_token'], 50 * MINUTE_IN_SECONDS );
	return $data['access_token'];
}
function ttseo_gsc_access_token() {
	return ttseo_google_token( 'https://www.googleapis.com/auth/webmasters.readonly' );
}

/* =========================================================================
 * GOOGLE SEARCH CONSOLE — Search Analytics
 * ========================================================================= */
function ttseo_gsc_query( $dimensions = array(), $row_limit = 25 ) {
	$property = ttseo_opt( 'gsc_property' );
	if ( ! $property ) {
		return new WP_Error( 'no_prop', ttseo_t( 'Chưa nhập GSC property.', 'GSC property not entered.' ) );
	}
	$cache_key = 'ttseo_gsc_' . md5( $property . implode( ',', $dimensions ) . $row_limit );
	$cached    = get_transient( $cache_key );
	if ( false !== $cached ) {
		return $cached;
	}
	$token = ttseo_gsc_access_token();
	if ( is_wp_error( $token ) ) {
		return $token;
	}
	$end   = gmdate( 'Y-m-d', time() - 3 * DAY_IN_SECONDS );
	$start = gmdate( 'Y-m-d', time() - 31 * DAY_IN_SECONDS );
	$body  = array( 'startDate' => $start, 'endDate' => $end, 'rowLimit' => $row_limit );
	if ( $dimensions ) {
		$body['dimensions'] = $dimensions;
	}
	$url  = 'https://searchconsole.googleapis.com/webmasters/v3/sites/' . rawurlencode( $property ) . '/searchAnalytics/query';
	$resp = wp_remote_post( $url, array(
		'timeout' => 20,
		'headers' => array( 'Authorization' => 'Bearer ' . $token, 'Content-Type' => 'application/json' ),
		'body'    => wp_json_encode( $body ),
	) );
	if ( is_wp_error( $resp ) ) {
		return $resp;
	}
	$code = wp_remote_retrieve_response_code( $resp );
	$data = json_decode( wp_remote_retrieve_body( $resp ), true );
	if ( 200 !== $code ) {
		return new WP_Error( 'gsc_http', ttseo_t( 'GSC API lỗi (', 'GSC API error (' ) . $code . '): ' . esc_html( $data['error']['message'] ?? '' ) );
	}
	$rows = $data['rows'] ?? array();
	set_transient( $cache_key, $rows, TTSEO_CACHE_TTL );
	return $rows;
}

/** Danh sách sitemap đã submit + số URL */
function ttseo_gsc_sitemaps() {
	$property = ttseo_opt( 'gsc_property' );
	if ( ! $property ) {
		return new WP_Error( 'no_prop', ttseo_t( 'Chưa nhập GSC property.', 'GSC property not entered.' ) );
	}
	$cache_key = 'ttseo_gsc_sm_' . md5( $property );
	$cached    = get_transient( $cache_key );
	if ( false !== $cached ) {
		return $cached;
	}
	$token = ttseo_gsc_access_token();
	if ( is_wp_error( $token ) ) {
		return $token;
	}
	$url  = 'https://searchconsole.googleapis.com/webmasters/v3/sites/' . rawurlencode( $property ) . '/sitemaps';
	$resp = wp_remote_get( $url, array( 'timeout' => 20, 'headers' => array( 'Authorization' => 'Bearer ' . $token ) ) );
	if ( is_wp_error( $resp ) ) {
		return $resp;
	}
	$data = json_decode( wp_remote_retrieve_body( $resp ), true );
	$sm   = $data['sitemap'] ?? array();
	set_transient( $cache_key, $sm, TTSEO_CACHE_TTL );
	return $sm;
}

/* =========================================================================
 * BING WEBMASTER
 * ========================================================================= */
function ttseo_bing_call( $method ) {
	$key  = ttseo_opt( 'bing_apikey' );
	$site = ttseo_opt( 'bing_siteurl', home_url( '/' ) );
	if ( ! $key ) {
		return new WP_Error( 'no_key', ttseo_t( 'Chưa nhập Bing API key.', 'Bing API key not entered.' ) );
	}
	$cache_key = 'ttseo_bing_' . md5( $method . $site );
	$cached    = get_transient( $cache_key );
	if ( false !== $cached ) {
		return $cached;
	}
	$url  = add_query_arg( array( 'apikey' => $key, 'siteUrl' => $site ), 'https://ssl.bing.com/webmaster/api.svc/json/' . $method );
	$resp = wp_remote_get( $url, array( 'timeout' => 20 ) );
	if ( is_wp_error( $resp ) ) {
		return $resp;
	}
	$data = json_decode( wp_remote_retrieve_body( $resp ), true );
	if ( isset( $data['ExceptionMessage'] ) || isset( $data['Message'] ) ) {
		return new WP_Error( 'bing_http', ttseo_t( 'Bing API lỗi: ', 'Bing API error: ' ) . esc_html( $data['ExceptionMessage'] ?? $data['Message'] ) );
	}
	$rows = $data['d'] ?? array();
	set_transient( $cache_key, $rows, TTSEO_CACHE_TTL );
	return $rows;
}

/* =========================================================================
 * GOOGLE ANALYTICS 4
 * ========================================================================= */
function ttseo_ga4_discover_property() {
	$token = ttseo_google_token( 'https://www.googleapis.com/auth/analytics.readonly' );
	if ( is_wp_error( $token ) ) {
		return $token;
	}
	$resp = wp_remote_get( 'https://analyticsadmin.googleapis.com/v1beta/accountSummaries', array(
		'timeout' => 20, 'headers' => array( 'Authorization' => 'Bearer ' . $token ),
	) );
	if ( is_wp_error( $resp ) ) {
		return $resp;
	}
	$data  = json_decode( wp_remote_retrieve_body( $resp ), true );
	$found = array();
	foreach ( ( $data['accountSummaries'] ?? array() ) as $acc ) {
		foreach ( ( $acc['propertySummaries'] ?? array() ) as $p ) {
			$id           = str_replace( 'properties/', '', $p['property'] ?? '' );
			$found[ $id ] = $p['displayName'] ?? $id;
		}
	}
	return $found;
}

function ttseo_ga4_report( $metrics, $dimensions = array(), $limit = 25, $order_metric = null ) {
	$pid = ttseo_opt( 'ga4_property_id' );
	if ( ! $pid ) {
		return new WP_Error( 'no_ga4', ttseo_t( 'Chưa nhập GA4 Property ID.', 'GA4 Property ID not entered.' ) );
	}
	$cache_key = 'ttseo_ga4_' . md5( $pid . implode( ',', $metrics ) . implode( ',', $dimensions ) . $limit );
	$cached    = get_transient( $cache_key );
	if ( false !== $cached ) {
		return $cached;
	}
	$token = ttseo_google_token( 'https://www.googleapis.com/auth/analytics.readonly' );
	if ( is_wp_error( $token ) ) {
		return $token;
	}
	$body = array(
		'dateRanges' => array( array( 'startDate' => '28daysAgo', 'endDate' => 'today' ) ),
		'metrics'    => array_map( function ( $m ) { return array( 'name' => $m ); }, $metrics ),
		'limit'      => $limit,
	);
	if ( $dimensions ) {
		$body['dimensions'] = array_map( function ( $d ) { return array( 'name' => $d ); }, $dimensions );
	}
	if ( $order_metric ) {
		$body['orderBys'] = array( array( 'desc' => true, 'metric' => array( 'metricName' => $order_metric ) ) );
	}
	$resp = wp_remote_post( 'https://analyticsdata.googleapis.com/v1beta/properties/' . rawurlencode( $pid ) . ':runReport', array(
		'timeout' => 20,
		'headers' => array( 'Authorization' => 'Bearer ' . $token, 'Content-Type' => 'application/json' ),
		'body'    => wp_json_encode( $body ),
	) );
	if ( is_wp_error( $resp ) ) {
		return $resp;
	}
	$code = wp_remote_retrieve_response_code( $resp );
	$data = json_decode( wp_remote_retrieve_body( $resp ), true );
	if ( 200 !== $code ) {
		return new WP_Error( 'ga4_http', ttseo_t( 'GA4 API lỗi (', 'GA4 API error (' ) . $code . '): ' . esc_html( $data['error']['message'] ?? '' ) );
	}
	set_transient( $cache_key, $data, TTSEO_CACHE_TTL );
	return $data;
}
function ttseo_ga4_metric_val( $report, $index = 0 ) {
	return $report['rows'][0]['metricValues'][ $index ]['value'] ?? 0;
}

/* =========================================================================
 * PAGESPEED INSIGHTS (Lighthouse) — không cần đăng nhập
 * ========================================================================= */
function ttseo_psi( $strategy = 'mobile' ) {
	$cache_key = 'ttseo_psi_' . $strategy;
	$cached    = get_transient( $cache_key );
	if ( false !== $cached ) {
		return $cached;
	}
	$args = array(
		'url'      => home_url( '/' ),
		'strategy' => $strategy,
		'category' => array( 'performance', 'seo', 'accessibility', 'best-practices' ),
	);
	$url = 'https://www.googleapis.com/pagespeedonline/v5/runPagespeed?' . http_build_query( $args );
	// http_build_query encodes category[] — PSI cần category lặp lại; build thủ công:
	$url = 'https://www.googleapis.com/pagespeedonline/v5/runPagespeed'
		. '?url=' . rawurlencode( home_url( '/' ) )
		. '&strategy=' . $strategy
		. '&category=performance&category=seo&category=accessibility&category=best-practices';
	$psi_key = ttseo_opt( 'psi_apikey' );
	if ( $psi_key ) {
		$url .= '&key=' . rawurlencode( $psi_key );
	}
	$resp = wp_remote_get( $url, array( 'timeout' => 60 ) );
	if ( is_wp_error( $resp ) ) {
		return $resp;
	}
	$data = json_decode( wp_remote_retrieve_body( $resp ), true );
	if ( empty( $data['lighthouseResult'] ) ) {
		return new WP_Error( 'psi_fail', ttseo_t( 'PSI chưa lấy được (có thể do giới hạn tần suất — thử lại sau vài phút hoặc thêm API key).', 'Could not fetch PSI (possibly rate-limited — try again in a few minutes or add an API key).' ) );
	}
	$lr   = $data['lighthouseResult'];
	$cats = $lr['categories'] ?? array();
	$au   = $lr['audits'] ?? array();
	$out  = array(
		'scores' => array(
			'performance'    => isset( $cats['performance']['score'] ) ? round( $cats['performance']['score'] * 100 ) : null,
			'seo'            => isset( $cats['seo']['score'] ) ? round( $cats['seo']['score'] * 100 ) : null,
			'accessibility'  => isset( $cats['accessibility']['score'] ) ? round( $cats['accessibility']['score'] * 100 ) : null,
			'best-practices' => isset( $cats['best-practices']['score'] ) ? round( $cats['best-practices']['score'] * 100 ) : null,
		),
		'cwv'    => array(
			'LCP' => $au['largest-contentful-paint']['displayValue'] ?? '—',
			'CLS' => $au['cumulative-layout-shift']['displayValue'] ?? '—',
			'TBT' => $au['total-blocking-time']['displayValue'] ?? '—',
			'FCP' => $au['first-contentful-paint']['displayValue'] ?? '—',
			'SI'  => $au['speed-index']['displayValue'] ?? '—',
		),
	);
	// Field data (CrUX) nếu có
	if ( ! empty( $data['loadingExperience']['metrics'] ) ) {
		$m = $data['loadingExperience']['metrics'];
		$out['field'] = array(
			'LCP' => isset( $m['LARGEST_CONTENTFUL_PAINT_MS'] ) ? round( $m['LARGEST_CONTENTFUL_PAINT_MS']['percentile'] / 1000, 2 ) . ' s' : null,
			'CLS' => isset( $m['CUMULATIVE_LAYOUT_SHIFT_SCORE'] ) ? ( $m['CUMULATIVE_LAYOUT_SHIFT_SCORE']['percentile'] / 100 ) : null,
			'INP' => isset( $m['INTERACTION_TO_NEXT_PAINT'] ) ? $m['INTERACTION_TO_NEXT_PAINT']['percentile'] . ' ms' : null,
		);
	}
	set_transient( $cache_key, $out, 12 * HOUR_IN_SECONDS );
	return $out;
}

/* =========================================================================
 * BỘ MÁY PHÂN TÍCH & CẢNH BÁO SEO
 * Trả về mảng insight: ['sev'=>good|opp|warn|crit, 'title'=>, 'detail'=>]
 * ========================================================================= */
function ttseo_analyze() {
	$insights = array();

	$totals  = ttseo_gsc_query( array(), 1 );
	$queries = ttseo_gsc_query( array( 'query' ), 100 );
	$pages   = ttseo_gsc_query( array( 'page' ), 100 );

	if ( is_wp_error( $totals ) || is_wp_error( $queries ) ) {
		return $insights; // GSC chưa kết nối — bỏ qua phân tích
	}

	$t   = $totals[0] ?? array();
	$ctr = (float) ( $t['ctr'] ?? 0 );
	$pos = (float) ( $t['position'] ?? 0 );

	// 1) Từ khóa "sát ngưỡng" trang 2 (vị trí 10.x–20) — cơ hội đẩy lên trang 1
	$striking = array();
	foreach ( (array) $queries as $r ) {
		$p = (float) ( $r['position'] ?? 0 );
		if ( $p > 10.5 && $p <= 20 ) {
			$striking[] = $r;
		}
	}
	usort( $striking, function ( $a, $b ) { return ( $b['impressions'] ?? 0 ) <=> ( $a['impressions'] ?? 0 ); } );
	if ( $striking ) {
		$top    = array_slice( $striking, 0, 5 );
		$list   = array();
		foreach ( $top as $r ) {
			$list[] = ( $r['keys'][0] ?? '' ) . ' (' . ttseo_t( 'vị trí', 'position' ) . ' ' . round( $r['position'], 1 ) . ', ' . (int) $r['impressions'] . ' ' . ttseo_t( 'hiển thị', 'impressions' ) . ')';
		}
		$insights[] = array(
			'sev'    => 'opp',
			'title'  => count( $striking ) . ' ' . ttseo_t( 'từ khóa đang ở TRANG 2 — cơ hội đẩy lên TOP nhanh nhất', 'keyword(s) are on PAGE 2 — the fastest opportunity to reach the TOP' ),
			'detail' => ttseo_t( 'Chỉ cần nhích vài bậc là lên trang 1. Ưu tiên tối ưu nội dung cho: ', 'Just a few positions away from page 1. Prioritize optimizing content for: ' ) . implode( ' · ', $list ),
		);
	}

	// 2) Từ khóa gần TOP (vị trí 4–10) — cú hích nhỏ để vào top 3
	$almost = array();
	foreach ( (array) $queries as $r ) {
		$p = (float) ( $r['position'] ?? 0 );
		if ( $p >= 3.5 && $p <= 10 ) {
			$almost[] = $r;
		}
	}
	if ( $almost ) {
		usort( $almost, function ( $a, $b ) { return ( $b['impressions'] ?? 0 ) <=> ( $a['impressions'] ?? 0 ); } );
		$names = array();
		foreach ( array_slice( $almost, 0, 4 ) as $r ) {
			$names[] = ( $r['keys'][0] ?? '' ) . ' (' . ttseo_t( 'v.trí', 'pos.' ) . ' ' . round( $r['position'], 1 ) . ')';
		}
		$insights[] = array(
			'sev'    => 'opp',
			'title'  => count( $almost ) . ' ' . ttseo_t( 'từ khóa ở nửa dưới trang 1 (vị trí 4–10)', 'keyword(s) on the lower half of page 1 (position 4–10)' ),
			'detail' => ttseo_t( 'Thêm backlink + tối ưu on-page để vào TOP 3: ', 'Add backlinks + on-page optimization to reach TOP 3: ' ) . implode( ' · ', $names ),
		);
	}

	// 3) Trang nhiều hiển thị nhưng CTR thấp — cần viết lại title/meta
	if ( ! is_wp_error( $pages ) ) {
		$lowctr = array();
		foreach ( (array) $pages as $r ) {
			$imp = (int) ( $r['impressions'] ?? 0 );
			$c   = (float) ( $r['ctr'] ?? 0 );
			$p   = (float) ( $r['position'] ?? 99 );
			if ( $imp >= 100 && $c < 0.01 && $p <= 20 ) {
				$lowctr[] = $r;
			}
		}
		usort( $lowctr, function ( $a, $b ) { return ( $b['impressions'] ?? 0 ) <=> ( $a['impressions'] ?? 0 ); } );
		if ( $lowctr ) {
			$urls = array();
			foreach ( array_slice( $lowctr, 0, 4 ) as $r ) {
				$path   = wp_parse_url( $r['keys'][0] ?? '', PHP_URL_PATH );
				$urls[] = $path . ' (' . (int) $r['impressions'] . ' ' . ttseo_t( 'hiển thị', 'impressions' ) . ', CTR ' . round( $r['ctr'] * 100, 2 ) . '%)';
			}
			$insights[] = array(
				'sev'    => 'warn',
				'title'  => count( $lowctr ) . ' ' . ttseo_t( 'trang nhiều hiển thị nhưng CTR rất thấp — viết lại tiêu đề/mô tả', 'page(s) with high impressions but very low CTR — rewrite title/description' ),
				'detail' => ttseo_t( 'Trang đang lên nhưng ít người bấm. Tối ưu title + meta description hấp dẫn hơn: ', 'The page is ranking but few people click. Optimize the title + meta description to be more compelling: ' ) . implode( ' · ', $urls ),
			);
		}
	}

	// 4) Top performer (vị trí ≤ 3)
	$top3 = 0;
	foreach ( (array) $queries as $r ) {
		if ( (float) ( $r['position'] ?? 99 ) <= 3 ) {
			$top3++;
		}
	}
	if ( $top3 > 0 ) {
		$insights[] = array(
			'sev'    => 'good',
			'title'  => $top3 . ' ' . ttseo_t( 'từ khóa đang trong TOP 3 Google', 'keyword(s) are in Google\'s TOP 3' ),
			'detail' => ttseo_t( 'Giữ vững bằng cách cập nhật nội dung định kỳ và xây thêm backlink trỏ về các trang này.', 'Maintain this by updating content regularly and building more backlinks to these pages.' ),
		);
	}

	// 5) CTR tổng thể
	if ( $ctr > 0 && $ctr < 0.015 ) {
		$insights[] = array(
			'sev'    => 'warn',
			'title'  => ttseo_t( 'CTR tổng thể thấp (', 'Overall CTR is low (' ) . round( $ctr * 100, 2 ) . '%)',
			'detail' => ttseo_t( 'Ngưỡng tốt cho B2B thường 2–4%. Cải thiện tiêu đề, thêm mô tả giàu lợi ích, dùng schema (sao đánh giá, FAQ) để nổi bật trên kết quả tìm kiếm.', 'A good B2B benchmark is usually 2–4%. Improve titles, add benefit-rich descriptions, and use schema (star ratings, FAQ) to stand out in search results.' ),
		);
	}

	// 6) Vị trí trung bình
	if ( $pos > 20 ) {
		$insights[] = array(
			'sev'    => 'warn',
			'title'  => ttseo_t( 'Vị trí trung bình còn thấp (', 'Average position is still low (' ) . round( $pos, 1 ) . ')',
			'detail' => ttseo_t( 'Phần lớn từ khóa chưa lên trang 1. Tập trung backlink + nội dung chuyên sâu cho nhóm từ khóa mục tiêu.', 'Most keywords haven\'t reached page 1 yet. Focus on backlinks + in-depth content for the target keyword group.' ),
		);
	}

	// 7) Index (Bing) vs sitemap
	$bing_crawl = ttseo_bing_call( 'GetCrawlStats' );
	if ( ! is_wp_error( $bing_crawl ) && ! empty( $bing_crawl ) ) {
		$inindex = (int) ( $bing_crawl[0]['InIndex'] ?? 0 );
		if ( $inindex > 0 && $inindex < 50 ) {
			$insights[] = array(
				'sev'    => 'warn',
				'title'  => ttseo_t( 'Số trang trong index Bing còn ít (', 'Few pages indexed on Bing (' ) . $inindex . ')',
				'detail' => ttseo_t( 'Kiểm tra sitemap đã submit trên Bing và dùng IndexNow (đã bật) để đẩy nhanh việc lập chỉ mục.', 'Check the sitemap submitted on Bing and use IndexNow (already enabled) to speed up indexing.' ),
			);
		}
	}

	// 8) PageSpeed
	$psi = ttseo_psi( 'mobile' );
	if ( ! is_wp_error( $psi ) ) {
		$perf = $psi['scores']['performance'] ?? null;
		if ( null !== $perf && $perf < 50 ) {
			$insights[] = array(
				'sev'    => 'crit',
				'title'  => ttseo_t( 'Điểm hiệu suất mobile thấp (', 'Low mobile performance score (' ) . $perf . '/100)',
				'detail' => ttseo_t( 'Tốc độ ảnh hưởng xếp hạng + trải nghiệm. Xem lại tối ưu ảnh, CSS/JS và Core Web Vitals bên dưới.', 'Speed affects both ranking and user experience. Review image, CSS/JS optimization and the Core Web Vitals below.' ),
			);
		}
		$seo = $psi['scores']['seo'] ?? null;
		if ( null !== $seo && $seo < 90 ) {
			$insights[] = array(
				'sev'    => 'warn',
				'title'  => ttseo_t( 'Điểm SEO kỹ thuật (Lighthouse) = ', 'Technical SEO score (Lighthouse) = ' ) . $seo . '/100',
				'detail' => ttseo_t( 'Còn lỗi on-page cơ bản Lighthouse phát hiện. Chạy PageSpeed Insights để xem chi tiết mục cần sửa.', 'Lighthouse found some basic on-page issues. Run PageSpeed Insights to see the details.' ),
			);
		}
	}

	if ( empty( $insights ) ) {
		$insights[] = array(
			'sev'    => 'good',
			'title'  => ttseo_t( 'Chưa phát hiện vấn đề nổi bật', 'No notable issues detected' ),
			'detail' => ttseo_t( 'Dữ liệu hiện tại ổn định. Tiếp tục theo dõi và xây backlink để tăng thứ hạng.', 'Current data looks stable. Keep monitoring and building backlinks to improve rankings.' ),
		);
	}
	return $insights;
}

/* =========================================================================
 * HELPERS
 * ========================================================================= */
function ttseo_b64url( $data ) { return rtrim( strtr( base64_encode( $data ), '+/', '-_' ), '=' ); }
function ttseo_num( $n ) { return number_format_i18n( (float) $n ); }
function ttseo_pct( $n ) { return number_format_i18n( (float) $n * 100, 2 ) . '%'; }

function ttseo_kpi( $label, $value, $sub = '', $accent = '#1f5c93' ) {
	echo '<div class="ttseo-kpi" style="--acc:' . esc_attr( $accent ) . '">';
	echo '<div class="ttseo-kpi-label">' . esc_html( $label ) . '</div>';
	echo '<div class="ttseo-kpi-val">' . esc_html( $value ) . '</div>';
	if ( $sub ) {
		echo '<div class="ttseo-kpi-sub">' . esc_html( $sub ) . '</div>';
	}
	echo '</div>';
}
function ttseo_score_color( $s ) {
	if ( null === $s ) { return '#8a8a8a'; }
	if ( $s >= 90 ) { return '#1a7f5a'; }
	if ( $s >= 50 ) { return '#c77d16'; }
	return '#c0392b';
}
function ttseo_err( $e ) {
	echo '<div class="notice notice-warning inline" style="margin:8px 0;"><p>⚠️ ' . esc_html( $e->get_error_message() ) . '</p></div>';
}

function ttseo_styles() {
	?>
	<style>
	.ttseo-wrap { max-width: 1120px; }
	.ttseo-wrap h2.ttseo-sec { font-size:17px; margin:34px 0 4px; padding-left:11px; border-left:4px solid var(--b,#1f5c93); }
	.ttseo-wrap .ttseo-subtle { color:#646970; font-size:13px; margin:2px 0 16px 15px; }
	.ttseo-strip { display:flex; gap:12px; flex-wrap:wrap; margin:14px 0; }
	.ttseo-kpi { flex:1; min-width:135px; background:#fff; border:1px solid #dcdfe3; border-top:3px solid var(--acc,#1f5c93); border-radius:8px; padding:13px 16px; }
	.ttseo-kpi-label { font-size:11px; letter-spacing:.04em; text-transform:uppercase; color:#646970; font-weight:600; }
	.ttseo-kpi-val { font-size:26px; font-weight:700; color:#1d2327; margin-top:3px; line-height:1.1; font-variant-numeric:tabular-nums; }
	.ttseo-kpi-sub { font-size:11px; color:#8a8f94; margin-top:2px; }
	.ttseo-insights { display:grid; gap:10px; margin:14px 0; }
	.ttseo-ins { display:grid; grid-template-columns:34px 1fr; gap:12px; background:#fff; border:1px solid #dcdfe3; border-left:4px solid var(--c); border-radius:8px; padding:12px 15px; }
	.ttseo-ins .ic { font-size:18px; line-height:1.4; }
	.ttseo-ins .t { font-weight:600; color:#1d2327; font-size:14px; }
	.ttseo-ins .d { color:#50575e; font-size:13px; margin-top:3px; line-height:1.5; }
	.ttseo-ins.good { --c:#1a7f5a; } .ttseo-ins.opp { --c:#1f5c93; } .ttseo-ins.warn { --c:#c77d16; } .ttseo-ins.crit { --c:#c0392b; }
	.ttseo-table { border:1px solid #dcdfe3; border-radius:8px; overflow:hidden; background:#fff; }
	.ttseo-table table { border-collapse:collapse; width:100%; }
	.ttseo-table th { text-align:left; font-size:11px; letter-spacing:.04em; text-transform:uppercase; color:#646970; padding:9px 13px; background:#f6f7f8; border-bottom:1px solid #dcdfe3; }
	.ttseo-table td { padding:9px 13px; border-top:1px solid #eef0f2; font-size:13.5px; font-variant-numeric:tabular-nums; }
	.ttseo-table tr:hover td { background:#f9fafb; }
	.ttseo-scores { display:flex; gap:14px; flex-wrap:wrap; margin:14px 0; }
	.ttseo-gauge { width:112px; text-align:center; background:#fff; border:1px solid #dcdfe3; border-radius:8px; padding:14px 6px; }
	.ttseo-gauge .ring { width:66px; height:66px; border-radius:50%; margin:0 auto 8px; display:flex; align-items:center; justify-content:center; font-weight:700; font-size:19px; color:#fff; }
	.ttseo-gauge .gl { font-size:11px; color:#646970; text-transform:uppercase; letter-spacing:.03em; }
	.ttseo-cwv { display:flex; gap:10px; flex-wrap:wrap; margin:6px 0 0; }
	.ttseo-cwv .c { background:#f6f7f8; border:1px solid #e4e6e9; border-radius:6px; padding:8px 13px; font-size:13px; }
	.ttseo-cwv .c b { display:block; font-size:16px; color:#1d2327; font-variant-numeric:tabular-nums; }
	.ttseo-src { display:inline-block; font-size:10px; font-weight:700; padding:1px 7px; border-radius:10px; vertical-align:middle; margin-left:8px; }
	.src-g { background:#e8f0fb; color:#1f5c93; } .src-b { background:#e3f3ef; color:#0f7a63; } .src-o { background:#fbeee0; color:#b96712; } .src-a { background:#f0e9fb; color:#6b3fb5; }
	</style>
	<?php
}

/* =========================================================================
 * DASHBOARD
 * ========================================================================= */
function ttseo_render_dashboard() {
	if ( ! ttseo_is_unlocked() ) {
		ttseo_render_gate();
		return;
	}
	ttseo_styles();
	$refresh_url = wp_nonce_url( admin_url( 'admin.php?page=ttseo-dashboard&ttseo_refresh=1' ), 'ttseo_refresh' );

	echo '<div class="wrap ttseo-wrap">';
	if ( function_exists( 'ttseo_brand_header' ) ) {
		ttseo_brand_header();
	}
	echo '<h1 style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;">📊 ' . esc_html( ttseo_t( 'SEO Dashboard', 'SEO Dashboard' ) ) . ' — Sun Reaches';
	if ( ! ttseo_is_pro() ) {
		echo ' <span style="font-size:11px;font-weight:700;color:#8a3ffc;background:#f2ebfe;padding:3px 9px;border-radius:10px;">FREE</span>';
	}
	echo ' <a href="' . esc_url( $refresh_url ) . '" class="button">↻ ' . esc_html( ttseo_t( 'Làm mới', 'Refresh' ) ) . '</a>';
	if ( current_user_can( 'manage_options' ) ) {
		echo ' <a href="' . esc_url( admin_url( 'admin.php?page=ttseo-settings' ) ) . '" class="button">⚙️ ' . esc_html( ttseo_t( 'Kết nối', 'Connections' ) ) . '</a>';
	}
	if ( ttseo_gate_enabled() ) {
		echo ' <a href="' . esc_url( admin_url( 'admin.php?page=ttseo-dashboard&ttseo_lock=1' ) ) . '" class="button">🔒 ' . esc_html( ttseo_t( 'Khóa lại', 'Lock' ) ) . '</a>';
	}
	if ( ! ttseo_is_pro() ) {
		echo ' <a href="https://sunreaches.com/seo-console/pricing" target="_blank" rel="noopener" class="button button-primary">⚡ ' . esc_html( ttseo_t( 'Nâng cấp Pro', 'Upgrade to Pro' ) ) . '</a>';
	}
	echo '</h1>';
	echo '<p class="ttseo-subtle" style="margin-left:0;">' . esc_html( ttseo_t( 'Nguồn: Google Search Console · Bing Webmaster · GA4 · PageSpeed Insights (API chính thức). Khoảng: 28 ngày. Cache 6 giờ.', 'Sources: Google Search Console · Bing Webmaster · GA4 · PageSpeed Insights (official APIs). Range: 28 days. Cache: 6 hours.' ) ) . '</p>';
	if ( isset( $_GET['refreshed'] ) ) {
		echo '<div class="notice notice-success is-dismissible"><p>' . esc_html( ttseo_t( 'Đã làm mới dữ liệu.', 'Data refreshed.' ) ) . '</p></div>';
	}

	$has_gsc  = ttseo_opt( 'gsc_sa_json' ) && ttseo_opt( 'gsc_property' );
	$has_bing = ttseo_opt( 'bing_apikey' );
	$has_ga4  = ttseo_opt( 'ga4_property_id' );

	if ( ! $has_gsc && ! $has_bing ) {
		echo '<div class="notice notice-info"><p>' . esc_html( ttseo_t( 'Chưa kết nối. Vào', 'Not connected yet. Go to' ) ) . ' <a href="' . esc_url( admin_url( 'admin.php?page=ttseo-settings' ) ) . '">' . esc_html( ttseo_t( 'Cài đặt kết nối', 'Connection Settings' ) ) . '</a>.</p></div></div>';
		return;
	}

	/* ---------- KPI TỔNG HỢP ---------- */
	$g_tot = $has_gsc ? ttseo_gsc_query( array(), 1 ) : new WP_Error( 'x', '' );
	$b_tra = $has_bing ? ttseo_bing_call( 'GetRankAndTrafficStats' ) : new WP_Error( 'x', '' );
	$psi   = ttseo_psi( 'mobile' );

	echo '<h2 class="ttseo-sec" style="--b:#1d2327;margin-top:20px;">' . esc_html( ttseo_t( 'Sức khỏe SEO — tổng hợp', 'SEO health — overview' ) ) . '</h2>';
	echo '<div class="ttseo-strip">';
	if ( ! is_wp_error( $g_tot ) && ! empty( $g_tot ) ) {
		$t = $g_tot[0];
		ttseo_kpi( 'Google Clicks', ttseo_num( $t['clicks'] ?? 0 ), ttseo_t( '28 ngày', '28 days' ), '#1f5c93' );
		ttseo_kpi( ttseo_t( 'Google Hiển thị', 'Google Impressions' ), ttseo_num( $t['impressions'] ?? 0 ), 'impressions', '#1f5c93' );
		ttseo_kpi( ttseo_t( 'Vị trí TB', 'Avg. position' ), number_format_i18n( (float) ( $t['position'] ?? 0 ), 1 ), 'Google', '#1f5c93' );
	}
	if ( ! is_wp_error( $b_tra ) ) {
		$bc = 0; $bi = 0;
		foreach ( (array) $b_tra as $r ) { $bc += (int) ( $r['Clicks'] ?? 0 ); $bi += (int) ( $r['Impressions'] ?? 0 ); }
		ttseo_kpi( 'Bing Clicks', ttseo_num( $bc ), 'Bing', '#0f7a63' );
		ttseo_kpi( ttseo_t( 'Bing Hiển thị', 'Bing Impressions' ), ttseo_num( $bi ), 'impressions', '#0f7a63' );
	}
	if ( ! is_wp_error( $psi ) && isset( $psi['scores']['performance'] ) ) {
		$p = $psi['scores']['performance'];
		ttseo_kpi( ttseo_t( 'Tốc độ (mobile)', 'Speed (mobile)' ), ( null === $p ? '—' : $p . '/100' ), 'PageSpeed', ttseo_score_color( $p ) );
	}
	echo '</div>';

	/* ---------- ENGAGEMENT (scroll/read/CTA/form tracking) ---------- */
	if ( function_exists( 'ttseo_render_engagement_card' ) ) {
		ttseo_render_engagement_card();
	}

	/* ---------- PHÂN TÍCH & CẢNH BÁO ---------- */
	if ( $has_gsc ) {
		echo '<h2 class="ttseo-sec" style="--b:#c77d16;">🔎 ' . esc_html( ttseo_t( 'Phân tích & Cảnh báo SEO', 'SEO Analysis & Alerts' ) ) . '</h2>';
		echo '<p class="ttseo-subtle">' . esc_html( ttseo_t( 'Tự động rút ra từ dữ liệu Google/Bing/PageSpeed — sắp theo cơ hội & mức độ ưu tiên.', 'Automatically derived from Google/Bing/PageSpeed data — sorted by opportunity & priority.' ) ) . '</p>';
		$icons = array( 'good' => '✅', 'opp' => '🚀', 'warn' => '⚠️', 'crit' => '🔴' );
		echo '<div class="ttseo-insights">';
		foreach ( ttseo_analyze() as $ins ) {
			echo '<div class="ttseo-ins ' . esc_attr( $ins['sev'] ) . '">';
			echo '<div class="ic">' . ( $icons[ $ins['sev'] ] ?? '•' ) . '</div>';
			echo '<div><div class="t">' . esc_html( $ins['title'] ) . '</div><div class="d">' . esc_html( $ins['detail'] ) . '</div></div>';
			echo '</div>';
		}
		echo '</div>';
	}

	/* ---------- GOOGLE ---------- */
	echo '<h2 class="ttseo-sec" style="--b:#1f5c93;">🔵 Google Search Console <span class="ttseo-src src-g">GSC</span></h2>';
	if ( ! $has_gsc ) {
		echo '<p class="ttseo-subtle">' . esc_html( ttseo_t( 'Chưa kết nối.', 'Not connected yet.' ) ) . ' <a href="' . esc_url( admin_url( 'admin.php?page=ttseo-settings' ) ) . '">' . esc_html( ttseo_t( 'Cấu hình →', 'Configure →' ) ) . '</a></p>';
	} elseif ( is_wp_error( $g_tot ) ) {
		ttseo_err( $g_tot );
	} else {
		$t = $g_tot[0] ?? array();
		echo '<div class="ttseo-strip">';
		ttseo_kpi( 'Clicks', ttseo_num( $t['clicks'] ?? 0 ) );
		ttseo_kpi( 'Impressions', ttseo_num( $t['impressions'] ?? 0 ) );
		ttseo_kpi( 'CTR', ttseo_pct( $t['ctr'] ?? 0 ) );
		ttseo_kpi( ttseo_t( 'Vị trí TB', 'Avg. position' ), number_format_i18n( (float) ( $t['position'] ?? 0 ), 1 ) );
		echo '</div>';

		// Device
		$dev = ttseo_gsc_query( array( 'device' ), 5 );
		if ( ! is_wp_error( $dev ) && $dev ) {
			echo '<h3>' . esc_html( ttseo_t( 'Theo thiết bị', 'By device' ) ) . '</h3><div class="ttseo-strip">';
			foreach ( $dev as $r ) {
				ttseo_kpi( ucfirst( strtolower( $r['keys'][0] ?? '' ) ), ttseo_num( $r['clicks'] ?? 0 ), ttseo_num( $r['impressions'] ?? 0 ) . ' ' . ttseo_t( 'hiển thị', 'impressions' ) );
			}
			echo '</div>';
		}

		echo '<h3>' . esc_html( ttseo_t( 'Top từ khóa', 'Top keywords' ) ) . '</h3>';
		ttseo_gsc_table( ttseo_gsc_query( array( 'query' ), 25 ), ttseo_t( 'Từ khóa', 'Keyword' ) );
		echo '<h3>' . esc_html( ttseo_t( 'Top trang', 'Top pages' ) ) . '</h3>';
		ttseo_gsc_table( ttseo_gsc_query( array( 'page' ), 25 ), ttseo_t( 'Trang', 'Page' ) );
		echo '<h3>' . esc_html( ttseo_t( 'Theo quốc gia', 'By country' ) ) . '</h3>';
		ttseo_gsc_table( ttseo_gsc_query( array( 'country' ), 15 ), ttseo_t( 'Quốc gia', 'Country' ) );

		// Sitemap / index
		$sm = ttseo_gsc_sitemaps();
		if ( ! is_wp_error( $sm ) && $sm ) {
			echo '<h3>' . esc_html( ttseo_t( 'Sitemap đã submit (Google)', 'Submitted sitemaps (Google)' ) ) . '</h3><div class="ttseo-table"><table><thead><tr><th>Sitemap</th><th>' . esc_html( ttseo_t( 'Loại', 'Type' ) ) . '</th><th>' . esc_html( ttseo_t( 'Đã gửi', 'Submitted' ) ) . '</th><th>' . esc_html( ttseo_t( 'Đã lập chỉ mục', 'Indexed' ) ) . '</th></tr></thead><tbody>';
			foreach ( $sm as $s ) {
				$path    = wp_parse_url( $s['path'] ?? '', PHP_URL_PATH );
				$content = $s['contents'][0] ?? array();
				echo '<tr><td>' . esc_html( $path ) . '</td><td>' . esc_html( $content['type'] ?? '—' ) . '</td><td>' . ttseo_num( $content['submitted'] ?? 0 ) . '</td><td>' . ttseo_num( $content['indexed'] ?? 0 ) . '</td></tr>';
			}
			echo '</tbody></table></div>';
		}
	}

	/* ---------- BING ---------- */
	echo '<h2 class="ttseo-sec" style="--b:#0f7a63;">🟢 Bing Webmaster <span class="ttseo-src src-b">Bing</span></h2>';
	if ( ! $has_bing ) {
		echo '<p class="ttseo-subtle">' . esc_html( ttseo_t( 'Chưa kết nối.', 'Not connected yet.' ) ) . '</p>';
	} else {
		if ( ! is_wp_error( $b_tra ) ) {
			$bc = 0; $bi = 0;
			foreach ( (array) $b_tra as $r ) { $bc += (int) ( $r['Clicks'] ?? 0 ); $bi += (int) ( $r['Impressions'] ?? 0 ); }
			echo '<div class="ttseo-strip">';
			ttseo_kpi( 'Clicks', ttseo_num( $bc ), '', '#0f7a63' );
			ttseo_kpi( 'Impressions', ttseo_num( $bi ), '', '#0f7a63' );
			ttseo_kpi( 'CTR', ttseo_pct( $bi ? $bc / $bi : 0 ), '', '#0f7a63' );
			echo '</div>';
		} else {
			ttseo_err( $b_tra );
		}
		$bq = ttseo_bing_call( 'GetQueryStats' );
		echo '<h3>' . esc_html( ttseo_t( 'Top từ khóa (Bing)', 'Top keywords (Bing)' ) ) . '</h3>';
		if ( ! is_wp_error( $bq ) && $bq ) {
			echo '<div class="ttseo-table"><table><thead><tr><th>' . esc_html( ttseo_t( 'Từ khóa', 'Keyword' ) ) . '</th><th>' . esc_html( ttseo_t( 'Hiển thị', 'Impressions' ) ) . '</th><th>Clicks</th><th>' . esc_html( ttseo_t( 'Vị trí TB', 'Avg. position' ) ) . '</th></tr></thead><tbody>';
			$i = 0;
			foreach ( (array) $bq as $r ) {
				if ( $i++ >= 25 ) { break; }
				echo '<tr><td>' . esc_html( $r['Query'] ?? '' ) . '</td><td>' . ttseo_num( $r['Impressions'] ?? 0 ) . '</td><td>' . ttseo_num( $r['Clicks'] ?? 0 ) . '</td><td>' . esc_html( $r['AvgImpressionPosition'] ?? '—' ) . '</td></tr>';
			}
			echo '</tbody></table></div>';
		} else {
			echo '<p class="ttseo-subtle">' . esc_html( ttseo_t( 'Chưa có dữ liệu.', 'No data yet.' ) ) . '</p>';
		}
		$crawl = ttseo_bing_call( 'GetCrawlStats' );
		if ( ! is_wp_error( $crawl ) && ! empty( $crawl ) ) {
			$last = $crawl[0];
			echo '<h3>' . esc_html( ttseo_t( 'Thu thập & lập chỉ mục (Bing)', 'Crawl & indexing (Bing)' ) ) . '</h3><div class="ttseo-strip">';
			ttseo_kpi( ttseo_t( 'Đã crawl', 'Crawled' ), ttseo_num( $last['CrawledPages'] ?? 0 ), ttseo_t( 'gần nhất', 'latest' ), '#0f7a63' );
			ttseo_kpi( ttseo_t( 'Trong Index', 'In index' ), ttseo_num( $last['InIndex'] ?? 0 ), '', '#0f7a63' );
			ttseo_kpi( ttseo_t( 'Lỗi crawl', 'Crawl errors' ), ttseo_num( $last['CrawlErrors'] ?? 0 ), '', '#c0392b' );
			echo '</div>';
		}
	}

	/* ---------- PAGESPEED ---------- */
	echo '<h2 class="ttseo-sec" style="--b:#b96712;">🟠 PageSpeed &amp; Core Web Vitals <span class="ttseo-src src-o">Lighthouse</span></h2>';
	if ( is_wp_error( $psi ) ) {
		ttseo_err( $psi );
	} else {
		echo '<p class="ttseo-subtle">' . esc_html( ttseo_t( 'Trang chủ (mobile). Đo bằng Google PageSpeed Insights — cache 12 giờ.', 'Homepage (mobile). Measured with Google PageSpeed Insights — cached 12 hours.' ) ) . '</p>';
		$labels = array( 'performance' => ttseo_t( 'Hiệu suất', 'Performance' ), 'seo' => 'SEO', 'accessibility' => ttseo_t( 'Tiếp cận', 'Accessibility' ), 'best-practices' => ttseo_t( 'Chuẩn mực', 'Best practices' ) );
		echo '<div class="ttseo-scores">';
		foreach ( $labels as $k => $lab ) {
			$s = $psi['scores'][ $k ] ?? null;
			echo '<div class="ttseo-gauge"><div class="ring" style="background:' . esc_attr( ttseo_score_color( $s ) ) . '">' . ( null === $s ? '—' : (int) $s ) . '</div><div class="gl">' . esc_html( $lab ) . '</div></div>';
		}
		echo '</div>';
		echo '<h3>Core Web Vitals (lab)</h3><div class="ttseo-cwv">';
		foreach ( $psi['cwv'] as $k => $v ) {
			echo '<div class="c">' . esc_html( $k ) . '<b>' . esc_html( $v ) . '</b></div>';
		}
		echo '</div>';
		if ( ! empty( $psi['field'] ) ) {
			echo '<h3>' . esc_html( ttseo_t( 'Dữ liệu thực tế người dùng (CrUX 28 ngày)', 'Real-user data (CrUX, 28 days)' ) ) . '</h3><div class="ttseo-cwv">';
			foreach ( $psi['field'] as $k => $v ) {
				if ( null !== $v ) {
					echo '<div class="c">' . esc_html( $k ) . '<b>' . esc_html( is_float( $v ) ? number_format( $v, 3 ) : $v ) . '</b></div>';
				}
			}
			echo '</div>';
		}
	}

	/* ---------- GA4 ---------- */
	echo '<h2 class="ttseo-sec" style="--b:#6b3fb5;">🟣 Google Analytics 4 <span class="ttseo-src src-a">GA4</span></h2>';
	if ( ! $has_ga4 ) {
		echo '<p class="ttseo-subtle">' . esc_html( ttseo_t( 'Chưa nhập GA4 Property ID.', 'GA4 Property ID not entered.' ) ) . '</p>';
	} else {
		$ov = ttseo_ga4_report( array( 'totalUsers', 'sessions', 'screenPageViews', 'averageSessionDuration', 'bounceRate' ) );
		if ( is_wp_error( $ov ) ) {
			ttseo_err( $ov );
			echo '<p class="ttseo-subtle">' . esc_html( ttseo_t( 'Đang chờ admin GA4 cấp quyền cho service account + bật Analytics Data/Admin API. Phần này tự hiện dữ liệu khi xong.', 'Waiting for the GA4 admin to grant access to the service account + enable the Analytics Data/Admin API. This section will populate automatically once done.' ) ) . '</p>';
		} else {
			$dur = (float) ttseo_ga4_metric_val( $ov, 3 );
			echo '<div class="ttseo-strip">';
			ttseo_kpi( ttseo_t( 'Người dùng', 'Users' ), ttseo_num( ttseo_ga4_metric_val( $ov, 0 ) ), '', '#6b3fb5' );
			ttseo_kpi( ttseo_t( 'Phiên', 'Sessions' ), ttseo_num( ttseo_ga4_metric_val( $ov, 1 ) ), '', '#6b3fb5' );
			ttseo_kpi( ttseo_t( 'Lượt xem trang', 'Page views' ), ttseo_num( ttseo_ga4_metric_val( $ov, 2 ) ), '', '#6b3fb5' );
			ttseo_kpi( ttseo_t( 'TG phiên TB', 'Avg. session duration' ), gmdate( 'i:s', (int) $dur ), ttseo_t( 'phút:giây', 'min:sec' ), '#6b3fb5' );
			ttseo_kpi( ttseo_t( 'Tỷ lệ thoát', 'Bounce rate' ), ttseo_pct( ttseo_ga4_metric_val( $ov, 4 ) ), '', '#6b3fb5' );
			echo '</div>';
			$ch = ttseo_ga4_report( array( 'sessions', 'totalUsers' ), array( 'sessionDefaultChannelGroup' ), 10, 'sessions' );
			echo '<h3>' . esc_html( ttseo_t( 'Nguồn truy cập (kênh)', 'Traffic source (channel)' ) ) . '</h3>';
			ttseo_ga4_table( $ch, ttseo_t( 'Kênh', 'Channel' ), array( ttseo_t( 'Phiên', 'Sessions' ), ttseo_t( 'Người dùng', 'Users' ) ) );
			$tp = ttseo_ga4_report( array( 'screenPageViews', 'totalUsers' ), array( 'pagePath' ), 20, 'screenPageViews' );
			echo '<h3>' . esc_html( ttseo_t( 'Trang xem nhiều nhất', 'Most-viewed pages' ) ) . '</h3>';
			ttseo_ga4_table( $tp, ttseo_t( 'Đường dẫn', 'Path' ), array( ttseo_t( 'Lượt xem', 'Views' ), ttseo_t( 'Người dùng', 'Users' ) ) );
		}
	}

	if ( function_exists( 'ttseo_brand_footer' ) ) {
		ttseo_brand_footer();
	}
	echo '</div>';
}

function ttseo_gsc_table( $rows, $label ) {
	if ( is_wp_error( $rows ) ) { ttseo_err( $rows ); return; }
	if ( empty( $rows ) ) { echo '<p class="ttseo-subtle">' . esc_html( ttseo_t( 'Chưa có dữ liệu.', 'No data yet.' ) ) . '</p>'; return; }
	echo '<div class="ttseo-table"><table><thead><tr><th>' . esc_html( $label ) . '</th><th>Clicks</th><th>' . esc_html( ttseo_t( 'Hiển thị', 'Impressions' ) ) . '</th><th>CTR</th><th>' . esc_html( ttseo_t( 'Vị trí', 'Position' ) ) . '</th></tr></thead><tbody>';
	foreach ( (array) $rows as $r ) {
		echo '<tr><td>' . esc_html( $r['keys'][0] ?? '' ) . '</td><td>' . ttseo_num( $r['clicks'] ?? 0 ) . '</td><td>' . ttseo_num( $r['impressions'] ?? 0 ) . '</td><td>' . ttseo_pct( $r['ctr'] ?? 0 ) . '</td><td>' . number_format_i18n( (float) ( $r['position'] ?? 0 ), 1 ) . '</td></tr>';
	}
	echo '</tbody></table></div>';
}

function ttseo_ga4_table( $report, $dim_label, $metric_labels ) {
	if ( is_wp_error( $report ) ) { ttseo_err( $report ); return; }
	$rows = $report['rows'] ?? array();
	if ( empty( $rows ) ) { echo '<p class="ttseo-subtle">' . esc_html( ttseo_t( 'Chưa có dữ liệu.', 'No data yet.' ) ) . '</p>'; return; }
	echo '<div class="ttseo-table"><table><thead><tr><th>' . esc_html( $dim_label ) . '</th>';
	foreach ( $metric_labels as $ml ) { echo '<th>' . esc_html( $ml ) . '</th>'; }
	echo '</tr></thead><tbody>';
	foreach ( $rows as $r ) {
		echo '<tr><td>' . esc_html( $r['dimensionValues'][0]['value'] ?? '' ) . '</td>';
		foreach ( $r['metricValues'] as $mv ) { echo '<td>' . ttseo_num( $mv['value'] ?? 0 ) . '</td>'; }
		echo '</tr>';
	}
	echo '</tbody></table></div>';
}

/* =========================================================================
 * SETTINGS PAGE
 * ========================================================================= */
function ttseo_render_settings() {
	if ( ! ttseo_is_unlocked() ) {
		ttseo_render_gate();
		return;
	}
	?>
	<div class="wrap">
		<h1>⚙️ <?php ttseo_e( 'Cấu hình', 'Settings' ); ?> — SEO Dashboard <span style="font-size:12px;color:#8a8f94;font-weight:400;">v<?php echo esc_html( TTSEO_VER ); ?></span></h1>
		<form method="post">
			<?php wp_nonce_field( 'ttseo_settings_save' ); ?>
			<input type="hidden" name="ttseo_modules_form" value="1">

			<h2 style="border-left:4px solid #1d2327;padding-left:10px;">🌐 <?php ttseo_e( 'Ngôn ngữ giao diện', 'Interface language' ); ?></h2>
			<table class="form-table">
				<tr><th><label><?php ttseo_e( 'Ngôn ngữ', 'Language' ); ?></label></th><td>
					<select name="ui_lang">
						<option value="vi" <?php selected( 'vi', ttseo_lang() ); ?>>Tiếng Việt</option>
						<option value="en" <?php selected( 'en', ttseo_lang() ); ?>>English</option>
					</select>
					<p class="description"><?php ttseo_e( 'Áp dụng cho khung sườn, menu và các trang Cấu hình / Người dùng &amp; Phân quyền. Một số màn hình module sẽ được song ngữ hoá dần ở các bản cập nhật sau.', 'Applies to the frame, menus, and the Settings / Users &amp; Permissions screens. Some module screens will be fully bilingual in upcoming updates.' ); ?></p>
				</td></tr>
			</table>

			<h2 style="border-left:4px solid #6b3fb5;padding-left:10px;">🧩 <?php ttseo_e( 'Module — bật/tắt phân hệ', 'Modules — enable/disable' ); ?></h2>
			<p class="description" style="margin:0 0 8px;"><?php ttseo_e( 'Tắt phân hệ không dùng để menu gọn hơn. Dữ liệu vẫn được giữ, bật lại là thấy.', 'Disable modules you don\'t use to keep the menu tidy. Data is kept and reappears when you re-enable a module.' ); ?></p>
			<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:10px;max-width:900px;margin-bottom:8px;">
			<?php foreach ( ttseo_modules_registry() as $slug => $info ) :
				$on = ttseo_module_on( $slug );
				$locked = 'analytics' === $slug; ?>
				<label style="display:flex;gap:10px;align-items:flex-start;background:#fff;border:1px solid #dcdfe3;border-radius:8px;padding:11px 13px;<?php echo $on ? 'border-left:3px solid #1a7f5a;' : 'border-left:3px solid #c9ccd0;opacity:.7;'; ?>">
					<input type="checkbox" name="module[<?php echo esc_attr( $slug ); ?>]" value="1" <?php checked( $on ); ?> <?php disabled( $locked ); ?> style="margin-top:2px;">
					<?php if ( $locked ) : ?><input type="hidden" name="module[<?php echo esc_attr( $slug ); ?>]" value="1"><?php endif; ?>
					<span>
						<b style="font-size:13px;"><?php echo esc_html( $info[0] ); ?></b><?php echo $locked ? ' <span style="font-size:10px;color:#8a8f94;">(' . esc_html( ttseo_t( 'lõi', 'core' ) ) . ')</span>' : ''; ?>
						<br><span style="font-size:11.5px;color:#646970;"><?php echo esc_html( $info[1] ); ?></span>
					</span>
				</label>
			<?php endforeach; ?>
			</div>

			<h2 style="border-left:4px solid #1f5c93;padding-left:10px;">🔵 Google Search Console</h2>
			<table class="form-table">
				<tr><th><label>GSC Property</label></th><td>
					<input name="gsc_property" type="text" class="regular-text" value="<?php echo esc_attr( ttseo_opt( 'gsc_property' ) ); ?>" placeholder="https://example.com/">
					<p class="description">URL-prefix: <code>https://example.com/</code> · Domain: <code>sc-domain:example.com</code></p>
				</td></tr>
				<tr><th><label>Service Account JSON</label></th><td>
					<textarea name="gsc_sa_json" rows="5" class="large-text code" placeholder='{ "type":"service_account", ... }'><?php echo esc_textarea( ttseo_opt( 'gsc_sa_json' ) ); ?></textarea>
					<p class="description"><?php ttseo_e( 'Dùng chung cho GSC + GA4. Nhớ add email service account vào GSC (và GA4) làm user.', 'Shared between GSC + GA4. Remember to add the service account email as a user in GSC (and GA4).' ); ?></p>
				</td></tr>
			</table>

			<h2 style="border-left:4px solid #6b3fb5;padding-left:10px;">🟣 Google Analytics 4</h2>
			<table class="form-table">
				<tr><th><label>GA4 Property ID</label></th><td>
					<input name="ga4_property_id" type="text" class="regular-text" value="<?php echo esc_attr( ttseo_opt( 'ga4_property_id' ) ); ?>" placeholder="510362087">
					<p class="description"><?php ttseo_e( 'Chỉ số (lấy từ URL GA4 sau chữ ', 'Numeric ID (from the GA4 URL after ' ); ?><code>p</code><?php ttseo_e( '). Cần add service account làm Viewer + bật Analytics Data/Admin API.', '). Requires adding the service account as Viewer + enabling the Analytics Data/Admin API.' ); ?></p>
				</td></tr>
			</table>

			<h2 style="border-left:4px solid #0f7a63;padding-left:10px;">🟢 Bing Webmaster</h2>
			<table class="form-table">
				<tr><th><label>Bing API Key</label></th><td>
					<input name="bing_apikey" type="text" class="regular-text" value="<?php echo esc_attr( ttseo_opt( 'bing_apikey' ) ); ?>">
					<p class="description">Bing Webmaster → Settings → API access → API Key.</p>
				</td></tr>
				<tr><th><label>Site URL (Bing)</label></th><td>
					<input name="bing_siteurl" type="text" class="regular-text" value="<?php echo esc_attr( ttseo_opt( 'bing_siteurl', home_url( '/' ) ) ); ?>">
				</td></tr>
			</table>

			<h2 style="border-left:4px solid #b96712;padding-left:10px;">🟠 PageSpeed Insights</h2>
			<table class="form-table">
				<tr><th><label>PSI API Key (<?php ttseo_e( 'tùy chọn', 'optional' ); ?>)</label></th><td>
					<input name="psi_apikey" type="text" class="regular-text" value="<?php echo esc_attr( ttseo_opt( 'psi_apikey' ) ); ?>">
					<p class="description"><?php ttseo_e( 'Để trống vẫn chạy (giới hạn tần suất). Có key thì ổn định hơn — tạo tại Google Cloud → Credentials → API Key.', 'Works fine left empty (rate-limited). Adding a key makes it more reliable — create one at Google Cloud → Credentials → API Key.' ); ?></p>
				</td></tr>
			</table>

			<h2 style="border-left:4px solid #1a7f5a;padding-left:10px;">📝 <?php ttseo_e( 'Soạn & Duyệt bài SEO', 'SEO Content & Approval' ); ?></h2>
			<table class="form-table">
				<tr><th><label><?php ttseo_e( 'Email người có quyền Duyệt/Từ chối bài', 'Email(s) with approve/reject rights' ); ?></label></th><td>
					<textarea name="client_emails" rows="3" class="large-text code" placeholder="reviewer@example.com"><?php echo esc_textarea( ttseo_opt( 'client_emails' ) ); ?></textarea>
					<p class="description"><?php ttseo_e( 'Mỗi dòng 1 email. Chỉ các tài khoản có email trong danh sách này mới thấy nút Duyệt bài / Yêu cầu chỉnh sửa. Để trống = mọi tài khoản có quyền truy cập đều duyệt được (không khuyến nghị lâu dài).', 'One email per line. Only accounts with an email in this list see the Approve / Request changes buttons. Leave empty = any account with dashboard access can approve (not recommended long-term).' ); ?></p>
				</td></tr>
				<tr><th><label><?php ttseo_e( 'Email nhận thông báo', 'Notification email' ); ?></label></th><td>
					<input name="notify_email" type="email" class="regular-text" value="<?php echo esc_attr( ttseo_opt( 'notify_email', get_option( 'admin_email' ) ) ); ?>">
					<p class="description"><?php ttseo_e( 'Nhận email khi có bài được duyệt hoặc yêu cầu chỉnh sửa.', 'Receives an email when a post is approved or changes are requested.' ); ?></p>
				</td></tr>
			</table>

			<h2 style="border-left:4px solid #c0392b;padding-left:10px;">🔒 <?php ttseo_e( 'Mật khẩu bảo vệ Dashboard', 'Dashboard password protection' ); ?></h2>
			<table class="form-table">
				<tr><th><label><?php ttseo_e( 'Đổi mật khẩu', 'Change password' ); ?></label></th><td>
					<input name="ttseo_new_pass" type="text" class="regular-text" value="" placeholder="<?php echo esc_attr( ttseo_gate_enabled() ? ttseo_t( 'Để trống nếu không đổi', 'Leave empty to keep unchanged' ) : ttseo_t( 'Đặt mật khẩu mới', 'Set a new password' ) ); ?>" autocomplete="off">
					<p class="description">
						<?php echo esc_html( ttseo_gate_enabled() ? ttseo_t( 'Đang bật khóa mật khẩu. Nhập mật khẩu mới để đổi (để trống = giữ nguyên). Xóa khóa: gõ ', 'Password lock is enabled. Enter a new password to change it (leave empty = unchanged). To remove the lock, type ' ) : ttseo_t( 'Chưa đặt. Nhập mật khẩu để bật khóa.', 'Not set. Enter a password to enable the lock.' ) ); ?><?php echo ttseo_gate_enabled() ? '<code>REMOVE</code>.' : ''; ?>
						<?php ttseo_e( 'Mật khẩu lưu dạng hash, không hiển thị lại.', 'Stored as a hash — never shown again.' ); ?>
					</p>
				</td></tr>
			</table>

			<p><button type="submit" name="ttseo_save" value="1" class="button button-primary"><?php ttseo_e( 'Lưu & kết nối', 'Save & connect' ); ?></button></p>
		</form>
	</div>
	<?php
}
