<?php
/**
 * Admin: menu, the three screens, form handlers, dashboard widget, upsell.
 *
 * Guideline 11 posture: everything this class renders lives under the
 * plugin's OWN menu. No site-wide admin notices, no dashboard takeovers —
 * the one dashboard widget summarizes and links, nothing more.
 *
 * @package SEO_Flight_Recorder
 */

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

/**
 * Class SFRec_Admin
 */
class SFRec_Admin {

	/**
	 * Wire hooks.
	 */
	public function init() {
		add_action( 'admin_menu', array( $this, 'menu' ) );
		add_action( 'admin_enqueue_scripts', array( $this, 'assets' ) );
		add_action( 'wp_dashboard_setup', array( $this, 'widget' ) );

		add_action( 'admin_post_sfrec_check_now', array( $this, 'handle_check_now' ) );
		add_action( 'admin_post_sfrec_add_page', array( $this, 'handle_add_page' ) );
		add_action( 'admin_post_sfrec_remove_page', array( $this, 'handle_remove_page' ) );
		add_action( 'admin_post_sfrec_change_status', array( $this, 'handle_change_status' ) );
		add_action( 'admin_post_sfrec_save_settings', array( $this, 'handle_save_settings' ) );
	}

	/**
	 * Menu: top-level page named after the plugin; Freemius appends its
	 * Upgrade/Account/Contact items under the same slug.
	 */
	public function menu() {
		add_menu_page(
			__( 'SEO Flight Recorder', 'buildsbyluke-seo-flight-recorder' ),
			__( 'SEO Flight Rec.', 'buildsbyluke-seo-flight-recorder' ),
			'manage_options',
			'seo-flight-recorder',
			array( $this, 'render_flight_log' ),
			'dashicons-visibility',
			81
		);
		add_submenu_page(
			'seo-flight-recorder',
			__( 'Flight Log', 'buildsbyluke-seo-flight-recorder' ),
			__( 'Flight Log', 'buildsbyluke-seo-flight-recorder' ),
			'manage_options',
			'seo-flight-recorder',
			array( $this, 'render_flight_log' )
		);
		add_submenu_page(
			'seo-flight-recorder',
			__( 'Monitored Pages', 'buildsbyluke-seo-flight-recorder' ),
			__( 'Monitored Pages', 'buildsbyluke-seo-flight-recorder' ),
			'manage_options',
			'sfrec-pages',
			array( $this, 'render_pages' )
		);
		add_submenu_page(
			'seo-flight-recorder',
			__( 'Settings', 'buildsbyluke-seo-flight-recorder' ),
			__( 'Settings', 'buildsbyluke-seo-flight-recorder' ),
			'manage_options',
			'sfrec-settings',
			array( $this, 'render_settings' )
		);
	}

	/**
	 * Admin CSS, only on our own screens.
	 *
	 * @param string $hook Current admin page hook.
	 */
	public function assets( $hook ) {
		if ( false === strpos( (string) $hook, 'seo-flight-recorder' ) && false === strpos( (string) $hook, 'sfrec-' ) ) {
			return;
		}
		wp_enqueue_style( 'sfrec-admin', SFREC_URL . 'admin/css/sfrec-admin.css', array(), SFREC_VERSION );
	}

	/**
	 * Screens.
	 */
	public function render_flight_log() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}
		require SFREC_DIR . 'admin/views/flight-log.php';
	}

	/**
	 * Monitored pages screen.
	 */
	public function render_pages() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}
		require SFREC_DIR . 'admin/views/pages.php';
	}

	/**
	 * Settings screen.
	 */
	public function render_settings() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}
		require SFREC_DIR . 'admin/views/settings.php';
	}

	/**
	 * Dashboard widget.
	 */
	public function widget() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}
		wp_add_dashboard_widget( 'sfrec_widget', __( 'SEO Flight Recorder', 'buildsbyluke-seo-flight-recorder' ), array( $this, 'render_widget' ) );
	}

	/**
	 * Widget body: the headline verdict.
	 */
	public function render_widget() {
		$counts = self::open_counts();
		$state  = get_option( 'sfrec_state', array() );

		if ( isset( $state['loopback_ok'] ) && false === $state['loopback_ok'] ) {
			echo '<p><strong>' . esc_html__( 'Monitoring impaired:', 'buildsbyluke-seo-flight-recorder' ) . '</strong> ' . esc_html__( 'this site cannot fetch its own pages (loopback failure). Checks cannot run.', 'buildsbyluke-seo-flight-recorder' ) . '</p>';
		} elseif ( $counts['critical'] > 0 ) {
			/* translators: %d: number of critical findings. */
			echo '<p><strong>' . esc_html( sprintf( _n( '%d critical SEO finding needs attention.', '%d critical SEO findings need attention.', $counts['critical'], 'buildsbyluke-seo-flight-recorder' ), $counts['critical'] ) ) . '</strong></p>';
		} elseif ( $counts['warning'] > 0 ) {
			/* translators: %d: number of warnings. */
			echo '<p>' . esc_html( sprintf( _n( '%d unreviewed SEO change.', '%d unreviewed SEO changes.', $counts['warning'], 'buildsbyluke-seo-flight-recorder' ), $counts['warning'] ) ) . '</p>';
		} else {
			echo '<p>' . esc_html__( 'No unreviewed SEO changes. The recorder is on duty.', 'buildsbyluke-seo-flight-recorder' ) . '</p>';
		}

		$last = isset( $state['last_check'] ) ? (int) $state['last_check'] : 0;
		if ( $last > 0 ) {
			/* translators: %s: human time diff. */
			echo '<p class="sfrec-muted">' . esc_html( sprintf( __( 'Last check: %s ago.', 'buildsbyluke-seo-flight-recorder' ), human_time_diff( $last ) ) ) . '</p>';
		}
		echo '<p><a href="' . esc_url( admin_url( 'admin.php?page=seo-flight-recorder' ) ) . '">' . esc_html__( 'Open the flight log', 'buildsbyluke-seo-flight-recorder' ) . '</a></p>';
	}

	/**
	 * The in-dashboard upsell card, rendered ONLY on the plugin's own Flight
	 * Log screen, ONLY for users without premium code.
	 *
	 * Every line below names something the free plugin genuinely does not do:
	 * Pro is the delivery lane that carries the flight log OUT of this site, to
	 * Slack, to your own systems, and to your clients. Everything that records,
	 * diffs, schedules, exposes or retains is free and unlimited — no line here
	 * may imply otherwise.
	 */
	public static function render_upsell() {
		if ( ! function_exists( 'sfrec_fs' ) || sfrec_fs()->can_use_premium_code() ) {
			return;
		}
		$trial_url   = sfrec_fs()->get_trial_url();
		$pricing_url = sfrec_fs()->get_upgrade_url();
		?>
		<div class="sfrec-upsell">
			<h2><?php esc_html_e( 'Need the flight log somewhere other than this dashboard?', 'buildsbyluke-seo-flight-recorder' ); ?></h2>
			<ul>
				<li><?php esc_html_e( 'Slack alerts — findings posted to the channel your team actually watches', 'buildsbyluke-seo-flight-recorder' ); ?></li>
				<li><?php esc_html_e( 'Outgoing webhooks — every run\'s changes as JSON, to your own endpoint', 'buildsbyluke-seo-flight-recorder' ); ?></li>
				<li><?php esc_html_e( 'White-label weekly client reports, emailed under your own brand', 'buildsbyluke-seo-flight-recorder' ); ?></li>
			</ul>
			<p class="sfrec-muted"><?php esc_html_e( 'Monitoring itself is not limited in any way: unlimited pages, every check frequency, the full flight log and its whole history are part of the free plugin.', 'buildsbyluke-seo-flight-recorder' ); ?></p>
			<p>
				<a class="button button-primary" href="<?php echo esc_url( $trial_url ); ?>"><?php esc_html_e( 'Start 14-day free trial — no card', 'buildsbyluke-seo-flight-recorder' ); ?></a>
				<a class="button" href="<?php echo esc_url( $pricing_url ); ?>"><?php esc_html_e( 'See plans', 'buildsbyluke-seo-flight-recorder' ); ?></a>
			</p>
		</div>
		<?php
	}

	/**
	 * Open finding counts for headline surfaces.
	 *
	 * @return array {critical, warning, info}
	 */
	public static function open_counts() {
		global $wpdb;
		$counts = array(
			'critical' => 0,
			'warning'  => 0,
			'info'     => 0,
		);
		$rows = $wpdb->get_results( "SELECT severity, COUNT(*) AS n FROM {$wpdb->prefix}sfrec_changes WHERE status IN ('new','seen') GROUP BY severity" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- own table.
		foreach ( (array) $rows as $row ) {
			if ( isset( $counts[ $row->severity ] ) ) {
				$counts[ $row->severity ] = (int) $row->n;
			}
		}
		return $counts;
	}

	// ------------------------------------------------------------------
	// Form handlers (admin-post). Every one: nonce + capability, then redirect.
	// ------------------------------------------------------------------

	/**
	 * "Check now".
	 */
	public function handle_check_now() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Insufficient permissions.', 'buildsbyluke-seo-flight-recorder' ) );
		}
		check_admin_referer( 'sfrec_check_now' );

		$result   = SFRec_Scanner::start_run( 'manual' );
		$message  = is_wp_error( $result ) ? 'run-active' : 'check-started';
		wp_safe_redirect( add_query_arg( 'sfrec_msg', $message, admin_url( 'admin.php?page=seo-flight-recorder' ) ) );
		exit;
	}

	/**
	 * Add a monitored page.
	 */
	public function handle_add_page() {
		global $wpdb;

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Insufficient permissions.', 'buildsbyluke-seo-flight-recorder' ) );
		}
		check_admin_referer( 'sfrec_add_page' );

		$url   = isset( $_POST['sfrec_url'] ) ? esc_url_raw( wp_unslash( $_POST['sfrec_url'] ) ) : '';
		$label = isset( $_POST['sfrec_label'] ) ? sanitize_text_field( wp_unslash( $_POST['sfrec_label'] ) ) : '';

		$home_host = wp_parse_url( home_url( '/' ), PHP_URL_HOST );
		$url_host  = wp_parse_url( $url, PHP_URL_HOST );

		$message = 'page-added';

		if ( '' === $url || ! $url_host || strtolower( (string) $url_host ) !== strtolower( (string) $home_host ) ) {
			$message = 'bad-url';
		} else {
			$already = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}sfrec_pages WHERE url_hash = %s", md5( $url ) ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- own table.
			if ( 0 === $already ) {
				$wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- own table.
					$wpdb->prefix . 'sfrec_pages',
					array(
						'url'       => $url,
						'url_hash'  => md5( $url ),
						'label'     => $label,
						'post_id'   => url_to_postid( $url ),
						'is_active' => 1,
						'added_at'  => gmdate( 'Y-m-d H:i:s' ),
					),
					array( '%s', '%s', '%s', '%d', '%d', '%s' )
				);
			}
		}

		wp_safe_redirect( add_query_arg( 'sfrec_msg', $message, admin_url( 'admin.php?page=sfrec-pages' ) ) );
		exit;
	}

	/**
	 * Remove a monitored page (and its snapshot; its log lines stay).
	 */
	public function handle_remove_page() {
		global $wpdb;

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Insufficient permissions.', 'buildsbyluke-seo-flight-recorder' ) );
		}
		$page_id = isset( $_POST['sfrec_page_id'] ) ? absint( $_POST['sfrec_page_id'] ) : 0;
		check_admin_referer( 'sfrec_remove_page_' . $page_id );

		if ( $page_id > 0 ) {
			$wpdb->delete( $wpdb->prefix . 'sfrec_pages', array( 'id' => $page_id ), array( '%d' ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- own table.
			$wpdb->delete( $wpdb->prefix . 'sfrec_snapshots', array( 'page_id' => $page_id ), array( '%d' ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- own table.
		}

		wp_safe_redirect( add_query_arg( 'sfrec_msg', 'page-removed', admin_url( 'admin.php?page=sfrec-pages' ) ) );
		exit;
	}

	/**
	 * Change-row status transitions (seen / resolved / muted) + optional note.
	 */
	public function handle_change_status() {
		global $wpdb;

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Insufficient permissions.', 'buildsbyluke-seo-flight-recorder' ) );
		}
		$change_id = isset( $_POST['sfrec_change_id'] ) ? absint( $_POST['sfrec_change_id'] ) : 0;
		check_admin_referer( 'sfrec_change_status_' . $change_id );

		$status  = isset( $_POST['sfrec_status'] ) ? sanitize_key( wp_unslash( $_POST['sfrec_status'] ) ) : '';
		$note    = isset( $_POST['sfrec_note'] ) ? sanitize_text_field( wp_unslash( $_POST['sfrec_note'] ) ) : '';
		$allowed = array( 'seen', 'resolved', 'muted', 'new' );

		if ( $change_id > 0 && in_array( $status, $allowed, true ) ) {
			$wpdb->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- own table.
				$wpdb->prefix . 'sfrec_changes',
				array(
					'status' => $status,
					'note'   => $note,
				),
				array( 'id' => $change_id ),
				array( '%s', '%s' ),
				array( '%d' )
			);

			// "Mute" also remembers the page+field pair so future identical
			// findings stay out of the log (the log records that decision).
			if ( 'muted' === $status ) {
				$row = $wpdb->get_row( $wpdb->prepare( "SELECT page_id, field FROM {$wpdb->prefix}sfrec_changes WHERE id = %d", $change_id ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- own table.
				if ( $row ) {
					$mutes   = get_option( 'sfrec_mutes', array() );
					$mutes   = is_array( $mutes ) ? $mutes : array();
					$mutes[] = (int) $row->page_id . '|' . $row->field;
					update_option( 'sfrec_mutes', array_values( array_unique( $mutes ) ), false );
				}
			}
		}

		wp_safe_redirect( add_query_arg( 'sfrec_msg', 'change-updated', admin_url( 'admin.php?page=seo-flight-recorder' ) ) );
		exit;
	}

	/**
	 * Settings save.
	 */
	public function handle_save_settings() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Insufficient permissions.', 'buildsbyluke-seo-flight-recorder' ) );
		}
		check_admin_referer( 'sfrec_save_settings' );

		$email     = isset( $_POST['sfrec_alert_email'] ) ? sanitize_email( wp_unslash( $_POST['sfrec_alert_email'] ) ) : '';
		$threshold = isset( $_POST['sfrec_email_threshold'] ) ? sanitize_key( wp_unslash( $_POST['sfrec_email_threshold'] ) ) : 'warning';
		if ( ! in_array( $threshold, array( 'info', 'warning', 'critical' ), true ) ) {
			$threshold = 'warning';
		}

		$frequency = isset( $_POST['sfrec_check_frequency'] ) ? sanitize_key( wp_unslash( $_POST['sfrec_check_frequency'] ) ) : 'daily';
		if ( 'off' !== $frequency && ! isset( SFRec_Scanner::frequencies()[ $frequency ] ) ) {
			$frequency = 'daily';
		}

		$retention = isset( $_POST['sfrec_retention_days'] ) ? absint( $_POST['sfrec_retention_days'] ) : 0;
		if ( ! in_array( $retention, array( 0, 30, 90, 180, 365 ), true ) ) {
			$retention = 0;
		}

		$settings = array(
			'alert_email'       => is_email( $email ) ? $email : get_option( 'admin_email' ),
			'email_alerts'      => isset( $_POST['sfrec_email_alerts'] ) ? 1 : 0,
			'email_threshold'   => $threshold,
			'email_all_clear'   => isset( $_POST['sfrec_email_all_clear'] ) ? 1 : 0,
			'check_frequency'   => $frequency,
			'post_update_check' => isset( $_POST['sfrec_post_update_check'] ) ? 1 : 0,
			'cache_bypass'      => isset( $_POST['sfrec_cache_bypass'] ) ? 1 : 0,
			'retention_days'    => $retention,
		);
		update_option( 'sfrec_settings', $settings );

		SFRec_Scanner::ensure_schedule();

		wp_safe_redirect( add_query_arg( 'sfrec_msg', 'settings-saved', admin_url( 'admin.php?page=sfrec-settings' ) ) );
		exit;
	}
}
