<?php
/**
 * Renders Settings → BW Dev. Vertical-sidebar layout: grouped sections (Core /
 * Editor & Admin / Front-end / Blocks) on the left, active section body on the
 * right. Modules and Branding live under Core; every enabled module appears
 * under its declared group(). All sections post to options.php using the
 * standard Settings API flow; BW_Dev_Settings::sanitize() dispatches per-tab.
 *
 * @package BW_Dev
 */

defined( 'ABSPATH' ) || exit;

class BW_Dev_Admin_Page {

	const MENU_SLUG = 'bw-dev';

	/**
	 * Group display order. Slugs match BW_Dev_Module_Interface::group() values.
	 *
	 * @var array<string,string> slug => raw English label (translated at render).
	 */
	private const GROUP_ORDER = array(
		'core'         => 'Core',
		'editor_admin' => 'Editor & Admin',
		'frontend'     => 'Front-end',
		'security'     => 'Security',
		'indexing'     => 'Indexing',
		'blocks'       => 'Blocks',
		'vendors'      => 'Vendors',
	);

	/**
	 * @var BW_Dev_Settings
	 */
	private $settings;

	/**
	 * @var BW_Dev_Module_Interface[]
	 */
	private $modules;

	/**
	 * @var BW_Dev_Brand|null
	 */
	private $brand;

	public function __construct( BW_Dev_Settings $settings, array $modules, ?BW_Dev_Brand $brand = null ) {
		$this->settings = $settings;
		$this->modules  = $modules;
		$this->brand    = $brand;
	}

	public function register(): void {
		add_action( 'admin_menu', array( $this, 'add_menu' ) );
	}

	public function add_menu(): void {
		$brand = $this->brand ? $this->brand->resolve() : array( 'plugin_display_name' => __( 'BW Dev', 'bw-dev' ) );
		$label = $brand['plugin_display_name'] ?: __( 'BW Dev', 'bw-dev' );
		add_options_page(
			$label,
			$label,
			'manage_options',
			self::MENU_SLUG,
			array( $this, 'render' )
		);
	}

	/**
	 * Active section from the URL, falling back to 'about'. Validates against
	 * the current section list so a stale bookmark (e.g. a now-disabled module)
	 * doesn't render an empty page. About is the default landing so first-time
	 * visitors (especially clients) see what the plugin is and why it matters
	 * before they encounter the module toggles.
	 *
	 * The Settings → BW Dev page is gated behind manage_options (see render()),
	 * so $_GET reads here are not a CSRF surface — they only select which
	 * section to display.
	 */
	private function active_tab(): string {
		$query     = wp_unslash( $_GET ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$requested = isset( $query['tab'] ) ? sanitize_key( (string) $query['tab'] ) : '';
		$valid     = $this->all_section_slugs();
		return isset( $valid[ $requested ] ) ? $requested : 'about';
	}

	private function was_settings_just_updated(): bool {
		$query = wp_unslash( $_GET ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		return isset( $query['settings-updated'] ) && 'true' === $query['settings-updated'];
	}

	/**
	 * Sidebar layout. Returns an ordered map of:
	 *   group_slug => [ 'label' => translated_label, 'sections' => [ section_slug => section_label ] ]
	 *
	 * Built-in sections (Modules, Branding) always live under Core. Enabled
	 * modules are placed under their declared group(); a module reporting an
	 * unknown group is folded into Core as a safe fallback. Empty groups are
	 * dropped so the sidebar doesn't render a heading with nothing under it.
	 *
	 * @return array<string,array{label:string,sections:array<string,string>}>
	 */
	private function layout(): array {
		$groups = array();
		foreach ( self::GROUP_ORDER as $slug => $raw_label ) {
			// translators: label for a settings sidebar group.
			$groups[ $slug ] = array(
				'label'    => $this->translated_group_label( $slug, $raw_label ),
				'sections' => array(),
			);
		}

		$groups['core']['sections']['about']    = __( 'About', 'bw-dev' );
		$groups['core']['sections']['modules']  = __( 'Modules', 'bw-dev' );
		$groups['core']['sections']['branding'] = __( 'Branding', 'bw-dev' );

		foreach ( $this->modules as $module ) {
			if ( ! $this->settings->is_module_enabled( $module->slug() ) ) {
				continue;
			}
			$group = $module->group();
			if ( ! isset( $groups[ $group ] ) ) {
				$group = 'core';
			}
			$groups[ $group ]['sections'][ $module->slug() ] = $module->label();
		}

		return array_filter(
			$groups,
			static function ( $g ) {
				return ! empty( $g['sections'] );
			}
		);
	}

	private function translated_group_label( string $slug, string $raw_label ): string {
		switch ( $slug ) {
			case 'core':
				return __( 'Core', 'bw-dev' );
			case 'editor_admin':
				return __( 'Editor & Admin', 'bw-dev' );
			case 'frontend':
				return __( 'Front-end', 'bw-dev' );
			case 'security':
				return __( 'Security', 'bw-dev' );
			case 'indexing':
				return __( 'Indexing', 'bw-dev' );
			case 'blocks':
				return __( 'Blocks', 'bw-dev' );
			case 'vendors':
				return __( 'Vendors', 'bw-dev' );
			default:
				return $raw_label;
		}
	}

	/**
	 * Flat slug => label map of every renderable section. Used to validate
	 * the ?tab= URL parameter.
	 */
	private function all_section_slugs(): array {
		$out = array();
		foreach ( $this->layout() as $group ) {
			foreach ( $group['sections'] as $slug => $label ) {
				$out[ $slug ] = $label;
			}
		}
		return $out;
	}

	public function render(): void {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'You do not have permission to access this page.', 'bw-dev' ) );
		}
		$active = $this->active_tab();
		$layout = $this->layout();
		?>
		<style>
			.bw-dev-shell { display:flex; gap:20px; align-items:flex-start; margin-top:14px; }
			.bw-dev-sidebar { flex:0 0 220px; background:#fff; border:1px solid #c3c4c7; padding:0; }
			.bw-dev-sidebar .bw-dev-group { border-bottom:1px solid #e0e0e0; padding:12px 0 8px; }
			.bw-dev-sidebar .bw-dev-group:last-child { border-bottom:0; }
			.bw-dev-sidebar .bw-dev-group-label {
				display:block; padding:0 14px 6px; font-size:11px; font-weight:600;
				text-transform:uppercase; letter-spacing:.04em; color:#646970;
			}
			.bw-dev-sidebar a {
				display:block; padding:7px 14px; color:#1d2327; text-decoration:none;
				border-left:3px solid transparent;
			}
			.bw-dev-sidebar a:hover { background:#f0f0f1; }
			.bw-dev-sidebar a.is-active {
				background:#f6f7f7; border-left-color:#2271b1; color:#2271b1; font-weight:600;
			}
			.bw-dev-content { flex:1; min-width:0; background:#fff; border:1px solid #c3c4c7; padding:16px 22px; }
			.bw-dev-content > h2:first-child { margin-top:0; }
			@media (max-width:782px) {
				.bw-dev-shell { flex-direction:column; }
				.bw-dev-sidebar { flex:1 1 auto; width:100%; }
			}
		</style>
		<div class="wrap">
			<h1><?php echo esc_html__( 'BW Dev', 'bw-dev' ); ?></h1>

			<?php if ( $this->was_settings_just_updated() ) : ?>
				<div class="notice notice-success is-dismissible">
					<p><?php esc_html_e( 'Settings saved.', 'bw-dev' ); ?></p>
				</div>
			<?php endif; ?>

			<div class="bw-dev-shell">
				<nav class="bw-dev-sidebar" aria-label="<?php esc_attr_e( 'BW Dev sections', 'bw-dev' ); ?>">
					<?php foreach ( $layout as $group ) : ?>
						<div class="bw-dev-group">
							<span class="bw-dev-group-label"><?php echo esc_html( $group['label'] ); ?></span>
							<?php
							foreach ( $group['sections'] as $section_slug => $section_label ) :
								$url = add_query_arg(
									array(
										'page' => self::MENU_SLUG,
										'tab'  => $section_slug,
									),
									admin_url( 'options-general.php' )
								);
								?>
								<a href="<?php echo esc_url( $url ); ?>" class="<?php echo $section_slug === $active ? 'is-active' : ''; ?>">
									<?php echo esc_html( $section_label ); ?>
								</a>
							<?php endforeach; ?>
						</div>
					<?php endforeach; ?>
				</nav>

				<div class="bw-dev-content">
					<form action="options.php" method="post">
						<?php settings_fields( BW_Dev_Settings::SETTING_GROUP ); ?>
						<input type="hidden" name="<?php echo esc_attr( BW_Dev_Settings::OPTION ); ?>[__tab]" value="<?php echo esc_attr( $active ); ?>" />

						<?php $this->render_section_body( $active ); ?>

						<?php if ( $this->section_has_form( $active ) ) : ?>
							<?php submit_button(); ?>
						<?php endif; ?>
					</form>
				</div>
			</div>
		</div>
		<?php
	}

	/**
	 * Whether the active section has any form fields worth submitting. Used
	 * to suppress the submit button (and the misleading "Settings saved"
	 * toast) on purely informational sections — About + any module that
	 * declares `default_settings()` as empty (post_link, flywheel_auto_updates,
	 * menu_visibility today).
	 */
	private function section_has_form( string $section ): bool {
		if ( 'about' === $section ) {
			return false;
		}
		if ( in_array( $section, array( 'modules', 'branding' ), true ) ) {
			return true;
		}
		foreach ( $this->modules as $module ) {
			if ( $module->slug() === $section ) {
				return ! empty( $module->default_settings() );
			}
		}
		return true;
	}

	private function render_section_body( string $section ): void {
		if ( 'about' === $section ) {
			echo '<h2>' . esc_html__( 'About', 'bw-dev' ) . '</h2>';
			$this->render_about_tab();
			return;
		}
		if ( 'modules' === $section ) {
			echo '<h2>' . esc_html__( 'Modules', 'bw-dev' ) . '</h2>';
			$this->render_modules_tab();
			return;
		}
		if ( 'branding' === $section ) {
			echo '<h2>' . esc_html__( 'Branding', 'bw-dev' ) . '</h2>';
			$this->render_branding_tab();
			return;
		}
		foreach ( $this->modules as $module ) {
			if ( $module->slug() === $section ) {
				echo '<h2>' . esc_html( $module->label() ) . '</h2>';
				$module->render_tab();
				return;
			}
		}
	}

	private function render_modules_tab(): void {
		// Bucket the modules by their declared group, preserving GROUP_ORDER.
		// Modules with an unknown group fold into 'core' (matches the sidebar).
		$by_group = array();
		foreach ( array_keys( self::GROUP_ORDER ) as $group_slug ) {
			$by_group[ $group_slug ] = array();
		}
		foreach ( $this->modules as $module ) {
			$g = $module->group();
			if ( ! isset( $by_group[ $g ] ) ) {
				$g = 'core';
			}
			$by_group[ $g ][] = $module;
		}
		?>
		<p class="description">
			<?php esc_html_e( 'Enable or disable individual BW Dev modules. Disabled modules register no hooks and add no overhead. Modules are grouped to match the sidebar.', 'bw-dev' ); ?>
		</p>

		<?php foreach ( $by_group as $group_slug => $group_modules ) :
			if ( empty( $group_modules ) ) {
				continue;
			}
			?>
			<h3 style="margin-top:24px;border-bottom:1px solid #c3c4c7;padding-bottom:6px;">
				<?php echo esc_html( $this->translated_group_label( $group_slug, self::GROUP_ORDER[ $group_slug ] ) ); ?>
			</h3>
			<table class="form-table" role="presentation">
				<tbody>
				<?php foreach ( $group_modules as $module ) :
					$slug     = $module->slug();
					$is_on    = $this->settings->is_module_enabled( $slug );
					$field_id = 'bw-dev-module-' . sanitize_html_class( $slug );
					$field_nm = BW_Dev_Settings::OPTION . '[modules][' . $slug . ']';
					?>
					<tr>
						<th scope="row"><?php echo esc_html( $module->label() ); ?></th>
						<td>
							<label for="<?php echo esc_attr( $field_id ); ?>">
								<input type="checkbox" id="<?php echo esc_attr( $field_id ); ?>" name="<?php echo esc_attr( $field_nm ); ?>" value="1" <?php checked( $is_on ); ?> />
								<?php esc_html_e( 'Enabled', 'bw-dev' ); ?>
							</label>
						</td>
					</tr>
				<?php endforeach; ?>
				</tbody>
			</table>
		<?php endforeach;
	}

	private function render_branding_tab(): void {
		$brand    = $this->brand ? $this->brand->resolve() : array();
		$defaults = $this->brand ? $this->brand->defaults() : array();
		$prefix   = BW_Dev_Settings::OPTION . '[brand]';
		?>
		<p class="description">
			<?php esc_html_e( 'White-label labels visible to clients. The block category label and block title prefix change what they see in the editor; the plugin display name changes the entry in the WordPress plugins list and the label of this Settings submenu. Tab names inside this page intentionally remain BW-branded.', 'bw-dev' ); ?>
		</p>

		<table class="form-table" role="presentation">
			<tbody>
				<tr>
					<th scope="row">
						<label for="bw-dev-brand-plugin-name"><?php esc_html_e( 'Plugin display name', 'bw-dev' ); ?></label>
					</th>
					<td>
						<input type="text" id="bw-dev-brand-plugin-name" name="<?php echo esc_attr( $prefix . '[plugin_display_name]' ); ?>" value="<?php echo esc_attr( (string) ( $brand['plugin_display_name'] ?? '' ) ); ?>" class="regular-text" placeholder="<?php echo esc_attr( (string) ( $defaults['plugin_display_name'] ?? 'BW Dev' ) ); ?>" />
						<p class="description"><?php esc_html_e( 'Shown in the WordPress plugins list and as the Settings submenu label. Leave blank for the default.', 'bw-dev' ); ?></p>
					</td>
				</tr>
				<tr>
					<th scope="row">
						<label for="bw-dev-brand-category-label"><?php esc_html_e( 'Block category label', 'bw-dev' ); ?></label>
					</th>
					<td>
						<input type="text" id="bw-dev-brand-category-label" name="<?php echo esc_attr( $prefix . '[block_category_label]' ); ?>" value="<?php echo esc_attr( (string) ( $brand['block_category_label'] ?? '' ) ); ?>" class="regular-text" placeholder="<?php echo esc_attr( (string) ( $defaults['block_category_label'] ?? 'BW Blocks' ) ); ?>" />
						<p class="description"><?php esc_html_e( 'Gutenberg category that groups all bw-dev blocks in the inserter.', 'bw-dev' ); ?></p>
					</td>
				</tr>
				<tr>
					<th scope="row">
						<label for="bw-dev-brand-title-prefix"><?php esc_html_e( 'Block title prefix', 'bw-dev' ); ?></label>
					</th>
					<td>
						<input type="text" id="bw-dev-brand-title-prefix" name="<?php echo esc_attr( $prefix . '[block_title_prefix]' ); ?>" value="<?php echo esc_attr( (string) ( $brand['block_title_prefix'] ?? '' ) ); ?>" class="regular-text" placeholder="<?php echo esc_attr( (string) ( $defaults['block_title_prefix'] ?? 'BW ' ) ); ?>" />
						<p class="description"><?php esc_html_e( 'Prepended to every bw-dev block title shown in the editor. Include a trailing space if you want one (e.g. "Acme "). Set to blank for no prefix.', 'bw-dev' ); ?></p>
					</td>
				</tr>
			</tbody>
		</table>
		<?php
	}

	/**
	 * Informational landing page. Visible to clients in `Settings → BW Dev`
	 * so they understand what the plugin is and don't disable/delete it.
	 * Always shows the underlying Bowden Works credits — the white-label
	 * layer covers plugin/block names, not authorship.
	 */
	private function render_about_tab(): void {
		$site_url = 'https://bowdenworks.com';
		$logo_url = BW_DEV_URL . 'assets/images/bowdenworks-logo.jpg';
		?>
		<style>
			.bw-dev-about p { max-width:720px; }
			.bw-dev-about .bw-dev-about-logo {
				display:block; max-width:260px; height:auto; margin:0 0 18px;
			}
			.bw-dev-about .bw-dev-about-callout {
				background:#f6f7f7; border-left:4px solid #2271b1; padding:12px 16px;
				margin:16px 0; max-width:720px;
			}
			.bw-dev-about .bw-dev-about-callout strong { color:#1d2327; }
			.bw-dev-about ul.bw-dev-about-credits { list-style:none; margin:8px 0 0; padding:0; max-width:720px; }
			.bw-dev-about ul.bw-dev-about-credits li { padding:4px 0; }
			.bw-dev-about .bw-dev-about-cta {
				display:inline-block; margin-top:6px; padding:8px 14px;
				background:#2271b1; color:#fff; text-decoration:none; border-radius:3px;
			}
			.bw-dev-about .bw-dev-about-cta:hover { background:#135e96; color:#fff; }
		</style>
		<div class="bw-dev-about">
			<a href="<?php echo esc_url( $site_url ); ?>" target="_blank" rel="noopener noreferrer">
				<img class="bw-dev-about-logo" src="<?php echo esc_url( $logo_url ); ?>" alt="<?php esc_attr_e( 'Bowden Works', 'bw-dev' ); ?>" width="260" />
			</a>
			<p>
				<?php esc_html_e( 'BW Dev is the in-house development toolkit Bowden Works installs on every WordPress site they build and maintain. It bundles essential admin enhancements, custom blocks, and front-end behaviors into a single actively-maintained plugin so each feature stays in sync across every site.', 'bw-dev' ); ?>
			</p>

			<div class="bw-dev-about-callout">
				<strong><?php esc_html_e( 'Why is this plugin installed on my site?', 'bw-dev' ); ?></strong>
				<p style="margin:6px 0 0;">
					<?php esc_html_e( 'BW Dev powers features your site relies on — favicon, sticky elements, custom Gutenberg blocks, menu visibility rules, admin notes, and more. Disabling or deleting it will break those features. The Bowden Works team maintains it directly and ships updates automatically.', 'bw-dev' ); ?>
				</p>
			</div>

			<h3><?php esc_html_e( 'About Bowden Works', 'bw-dev' ); ?></h3>
			<p>
				<?php esc_html_e( 'Bowden Works is a web development and digital marketing agency based in Courtenay, British Columbia, Canada. With two decades of experience, they specialise in WordPress development, technical SEO, ads management, analytics, and white-label services for other agencies. Their tagline: "Your behind-the-scenes partner in digital excellence."', 'bw-dev' ); ?>
			</p>
			<p>
				<a class="bw-dev-about-cta" href="<?php echo esc_url( $site_url ); ?>" target="_blank" rel="noopener noreferrer">
					<?php
					/* translators: %s: bowdenworks.com */
					echo esc_html( sprintf( __( 'Visit %s', 'bw-dev' ), 'bowdenworks.com' ) );
					?>
				</a>
			</p>

			<h3><?php esc_html_e( 'Credits', 'bw-dev' ); ?></h3>
			<p>
				<?php esc_html_e( 'Built and maintained by the Bowden Works team:', 'bw-dev' ); ?>
			</p>
			<ul class="bw-dev-about-credits">
				<li>
					<strong>Rian Bowden</strong> &mdash;
					<a href="mailto:rian@rian.ca">rian@rian.ca</a>
				</li>
				<li>
					<strong>Adi Pramono</strong> &mdash;
					<a href="mailto:info@adipramono.com">info@adipramono.com</a>
				</li>
			</ul>

			<h3><?php esc_html_e( 'Need Help?', 'bw-dev' ); ?></h3>
			<p>
				<?php esc_html_e( 'If you have questions about BW Dev or notice anything not working as expected, please contact the Bowden Works team:', 'bw-dev' ); ?>
				<a href="mailto:info@bowdenworks.com">info@bowdenworks.com</a>.
			</p>

			<p class="description" style="margin-top:24px;">
				<?php
				printf(
					/* translators: %s: BW_DEV_VERSION constant value */
					esc_html__( 'BW Dev version %s', 'bw-dev' ),
					esc_html( defined( 'BW_DEV_VERSION' ) ? BW_DEV_VERSION : '0.0.0' )
				);
				?>
			</p>
		</div>
		<?php
	}
}
