<?php
/**
 * Brentwood Timetable — content management via ACF Options Page.
 *
 * The weekly grid (days, blocks, times, rotation) stays developer-maintained in
 * blocks/timetable/grid.php. What editors can manage here is the *content* of the
 * per-category panels that appear when a category block is clicked: the heading,
 * body text, images, and the "Learn more" link.
 *
 * Editing happens on the "Timetable" admin page (ACF Options Page). Values are
 * overlaid on top of the code defaults (bw_timetable_panel_defaults()), so:
 *   - structural keys (`style`, `inline`) and the category set stay in code;
 *   - if ACF is unavailable or a field is blank, the original static content
 *     shows — nothing breaks.
 *
 * The options page is seeded once from the static defaults so editors start with
 * the existing content already filled in, ready to edit.
 *
 * @package kadence-child
 */

defined( 'ABSPATH' ) || exit;

// Code defaults live with the grid definition; make sure they're available.
$bw_tt_grid = get_stylesheet_directory() . '/blocks/timetable/grid.php';
if ( is_readable( $bw_tt_grid ) ) {
	require_once $bw_tt_grid;
}

/**
 * Canonical category slug => label map. Drives the ACF category <select> choices
 * and the seeding order. Keep in sync with bw_timetable_panel_defaults() and the
 * choices in acf-json/group_bwm_timetable.json.
 *
 * @return array<string,string>
 */
function bw_tt_categories() {
	return array(
		'academics'  => 'Period (Academics)',
		'arts'       => 'Art Blocks',
		'athletics'  => 'Athletics',
		'food'       => 'Food',
		'advisor'    => 'Advisor',
		'tutorial'   => 'Tutorial',
		'assembly'   => 'Assembly',
		'sleep-in'   => 'Sleep-In',
		'prep'       => 'Evening Prep',
		'activities' => 'Evening Activity',
	);
}

/**
 * Resolve a stored category value (which may be a slug OR a friendly label) back
 * to its canonical slug. Returns '' if unrecognised.
 *
 * @param string $value
 * @return string
 */
function bw_tt_resolve_slug( $value ) {
	$value = trim( (string) $value );
	if ( '' === $value ) {
		return '';
	}
	$cats = bw_tt_categories();
	if ( isset( $cats[ $value ] ) ) {
		return $value; // Already a slug.
	}
	foreach ( $cats as $slug => $label ) {
		if ( 0 === strcasecmp( $label, $value ) ) {
			return $slug;
		}
	}
	return '';
}

/**
 * Per-category panels with ACF content overlaid on the code defaults.
 * This replaces the old static bw_timetable_panels(); render.php calls it
 * unchanged.
 *
 * @return array<string,array>
 */
function bw_timetable_panels() {
	$defaults = function_exists( 'bw_timetable_panel_defaults' ) ? bw_timetable_panel_defaults() : array();

	if ( ! function_exists( 'get_field' ) ) {
		return $defaults;
	}

	$rows = get_field( 'tt_panels', 'option' );
	if ( empty( $rows ) || ! is_array( $rows ) ) {
		return $defaults;
	}

	$panels = $defaults;
	foreach ( $rows as $row ) {
		$cat = isset( $row['tt_category'] ) ? bw_tt_resolve_slug( $row['tt_category'] ) : '';
		if ( '' === $cat || ! isset( $panels[ $cat ] ) ) {
			continue; // Only override categories that exist in the grid.
		}

		$panel = $panels[ $cat ];

		if ( isset( $row['tt_header'] ) && '' !== trim( (string) $row['tt_header'] ) ) {
			$panel['header'] = $row['tt_header'];
		}
		if ( isset( $row['tt_body'] ) && '' !== trim( wp_strip_all_tags( (string) $row['tt_body'] ) ) ) {
			$panel['body'] = $row['tt_body'];
		}
		// Link + link text: allow explicit empties (an editor clearing the CTA).
		if ( array_key_exists( 'tt_link', $row ) ) {
			$panel['link'] = (string) $row['tt_link'];
		}
		if ( array_key_exists( 'tt_link_text', $row ) ) {
			$panel['link_text'] = (string) $row['tt_link_text'];
		}
		// Panel Image — the single photo shown in the expanded text panel.
		if ( ! empty( $row['tt_image'] ) ) {
			$panel['image'] = (int) $row['tt_image'];
		}
		// Block Background Images — the faint photos behind this category's grid
		// blocks (cycled across them).
		if ( ! empty( $row['tt_gallery'] ) && is_array( $row['tt_gallery'] ) ) {
			$ids = array_values( array_filter( array_map( 'intval', $row['tt_gallery'] ) ) );
			if ( $ids ) {
				$panel['images'] = $ids;
			}
		}

		$panels[ $cat ] = $panel;
	}

	return $panels;
}

/**
 * Overlay editable rotation content (from the ACF options page) on top of the
 * code defaults supplied by bw_timetable_grid(). Hooked on `bw_timetable_rotation`.
 * Any field left blank keeps the developer default — nothing breaks.
 *
 * @param array $rotation Default rotation (title, days[], periods[name=>letters[]], colors[L=>hex]).
 * @return array
 */
function bw_tt_rotation_overlay( $rotation ) {
	if ( ! function_exists( 'get_field' ) ) {
		return $rotation;
	}

	$title = get_field( 'tt_rot_title', 'option' );
	if ( is_string( $title ) && '' !== trim( $title ) ) {
		$rotation['title'] = $title;
	}

	$days_raw = get_field( 'tt_rot_days', 'option' );
	if ( is_string( $days_raw ) && '' !== trim( $days_raw ) ) {
		$days = array_values( array_filter( array_map( 'trim', preg_split( '/\r\n|\r|\n/', $days_raw ) ) ) );
		if ( $days ) {
			$rotation['days'] = $days;
		}
	}

	$periods = get_field( 'tt_rot_periods', 'option' );
	if ( ! empty( $periods ) && is_array( $periods ) ) {
		$out = array();
		foreach ( $periods as $p ) {
			$name    = isset( $p['tt_rot_period_name'] ) ? trim( $p['tt_rot_period_name'] ) : '';
			$letters = isset( $p['tt_rot_period_letters'] ) ? $p['tt_rot_period_letters'] : '';
			$letters = array_values( array_filter( array_map( 'trim', preg_split( '/[,\s]+/', (string) $letters ) ) ) );
			if ( '' !== $name && $letters ) {
				$out[ $name ] = $letters;
			}
		}
		if ( $out ) {
			$rotation['periods'] = $out;
		}
	}

	$colors = get_field( 'tt_rot_colors', 'option' );
	if ( ! empty( $colors ) && is_array( $colors ) ) {
		$out = array();
		foreach ( $colors as $c ) {
			$letter = isset( $c['tt_rot_color_letter'] ) ? strtoupper( trim( $c['tt_rot_color_letter'] ) ) : '';
			$value  = isset( $c['tt_rot_color_value'] ) ? trim( $c['tt_rot_color_value'] ) : '';
			if ( '' !== $letter && '' !== $value ) {
				$out[ $letter ] = $value;
			}
		}
		if ( $out ) {
			$rotation['colors'] = $out;
		}
	}

	return $rotation;
}
add_filter( 'bw_timetable_rotation', 'bw_tt_rotation_overlay' );

/**
 * Seed the rotation fields once from the code defaults (when still empty), so the
 * editor starts with the current title / day headers / letters / colours filled in.
 */
function bw_tt_seed_rotation() {
	if ( ! function_exists( 'get_field' ) || ! function_exists( 'update_field' ) || ! function_exists( 'bw_timetable_grid' ) ) {
		return;
	}
	if ( '' !== (string) get_field( 'tt_rot_title', 'option' ) ) {
		return; // already seeded / edited.
	}

	$grid = bw_timetable_grid();
	$rot  = isset( $grid['rotation'] ) ? $grid['rotation'] : array();
	if ( empty( $rot ) ) {
		return;
	}

	update_field( 'tt_rot_title', isset( $rot['title'] ) ? $rot['title'] : 'Academic Block Rotation', 'option' );
	update_field( 'tt_rot_days', isset( $rot['days'] ) ? implode( "\n", $rot['days'] ) : '', 'option' );

	$periods = array();
	if ( ! empty( $rot['periods'] ) ) {
		foreach ( $rot['periods'] as $name => $letters ) {
			$periods[] = array(
				'tt_rot_period_name'    => $name,
				'tt_rot_period_letters' => implode( ', ', (array) $letters ),
			);
		}
	}
	update_field( 'tt_rot_periods', $periods, 'option' );

	$colors = array();
	if ( ! empty( $rot['colors'] ) ) {
		foreach ( $rot['colors'] as $letter => $value ) {
			$colors[] = array(
				'tt_rot_color_letter' => $letter,
				'tt_rot_color_value'  => $value,
			);
		}
	}
	update_field( 'tt_rot_colors', $colors, 'option' );
}

/**
 * Register the "Timetable" ACF Options Page.
 */
add_action(
	'acf/init',
	function () {
		if ( ! function_exists( 'acf_add_options_page' ) ) {
			return;
		}
		acf_add_options_page(
			array(
				'page_title'  => 'Edit Timetable Content',
				'menu_title'  => 'Timetable',
				'menu_slug'   => 'timetable-management',
				'capability'  => 'edit_pages',
				'icon_url'    => 'dashicons-calendar-alt',
				'position'    => 58,
				'redirect'    => false,
				'description' => 'Update the text and images shown in the Brentwood Timetable category panels. The schedule grid itself is fixed in the theme.',
			)
		);
	}
);

/**
 * Seed the options page once from the static defaults, so editors begin with the
 * current content already filled in. Runs only in the admin / WP-CLI, guarded by
 * a one-time flag and an emptiness check.
 */
add_action(
	'acf/init',
	function () {
		if ( ! is_admin() && ! ( defined( 'WP_CLI' ) && WP_CLI ) ) {
			return;
		}
		if ( get_option( 'bw_tt_panels_seeded_v2' ) ) {
			return;
		}
		if ( ! function_exists( 'get_field' ) || ! function_exists( 'update_field' ) || ! function_exists( 'bw_timetable_panel_defaults' ) ) {
			return;
		}

		// Seed the Academic Block Rotation fields (independent of the panels).
		bw_tt_seed_rotation();

		$defaults = bw_timetable_panel_defaults();
		$existing = get_field( 'tt_panels', 'option' );

		if ( ! empty( $existing ) && is_array( $existing ) ) {
			// A v1 seed (single gallery) already ran — backfill the new Panel Image
			// field per row from the code default; leave everything else untouched.
			$changed = false;
			foreach ( $existing as $i => $row ) {
				$cat = isset( $row['tt_category'] ) ? $row['tt_category'] : '';
				if ( empty( $row['tt_image'] ) && isset( $defaults[ $cat ]['image'] ) ) {
					$existing[ $i ]['tt_image'] = (int) $defaults[ $cat ]['image'];
					$changed = true;
				}
			}
			if ( $changed ) {
				update_field( 'tt_panels', $existing, 'option' );
			}
			update_option( 'bw_tt_panels_seeded_v2', 1 );
			return;
		}

		$labels = bw_tt_categories();
		$rows   = array();
		foreach ( $defaults as $slug => $panel ) {
			$rows[] = array(
				'tt_category'  => isset( $labels[ $slug ] ) ? $labels[ $slug ] : $slug,
				'tt_header'    => isset( $panel['header'] ) ? $panel['header'] : '',
				'tt_body'      => isset( $panel['body'] ) ? $panel['body'] : '',
				'tt_image'     => isset( $panel['image'] ) ? (int) $panel['image'] : '',
				'tt_gallery'   => isset( $panel['images'] ) ? array_map( 'intval', (array) $panel['images'] ) : array(),
				'tt_link'      => isset( $panel['link'] ) ? $panel['link'] : '',
				'tt_link_text' => isset( $panel['link_text'] ) ? $panel['link_text'] : '',
			);
		}

		update_field( 'tt_panels', $rows, 'option' );
		update_option( 'bw_tt_panels_seeded_v2', 1 );
	},
	20
);

/**
 * Migrate stored category values from slugs to friendly labels (one-off), so the
 * read-only Category text and the collapsed row title read nicely. Idempotent.
 */
add_action(
	'acf/init',
	function () {
		if ( ! is_admin() && ! ( defined( 'WP_CLI' ) && WP_CLI ) ) {
			return;
		}
		if ( get_option( 'bw_tt_cat_labels_v1' ) ) {
			return;
		}
		if ( ! function_exists( 'get_field' ) || ! function_exists( 'update_field' ) ) {
			return;
		}
		$rows = get_field( 'tt_panels', 'option' );
		if ( empty( $rows ) || ! is_array( $rows ) ) {
			return; // Nothing yet; the seeder already writes labels.
		}
		$labels  = bw_tt_categories();
		$changed = false;
		foreach ( $rows as $i => $row ) {
			$v = isset( $row['tt_category'] ) ? (string) $row['tt_category'] : '';
			if ( isset( $labels[ $v ] ) ) { // Stored as slug — convert to label.
				$rows[ $i ]['tt_category'] = $labels[ $v ];
				$changed                   = true;
			}
		}
		if ( $changed ) {
			update_field( 'tt_panels', $rows, 'option' );
		}
		update_option( 'bw_tt_cat_labels_v1', 1 );
	},
	21
);

/**
 * Admin polish for the Timetable options page only:
 *  - render the (read-only) Category value as a bold colour-coded heading;
 *  - tint each panel row with its category colour so it's obvious which editor
 *    belongs to which category;
 *  - disable drag-reordering (Add/Remove are already hidden by min=max=10).
 */
add_action(
	'admin_head',
	function () {
		$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
		if ( ! $screen || false === strpos( (string) $screen->id, 'timetable-management' ) ) {
			return;
		}

		// Category colours (from the timetable grid). Keyed by both slug and label
		// so the JS can match whatever the row currently stores.
		$colors = array(
			'academics'  => '#e11d48',
			'arts'       => '#8b5cf6',
			'athletics'  => '#10b981',
			'food'       => '#fb923c',
			'advisor'    => '#ef4444',
			'tutorial'   => '#ef4444',
			'assembly'   => '#3b82f6',
			'sleep-in'   => '#0ea5e9',
			'prep'       => '#ef4444',
			'activities' => '#0ea5e9',
		);
		$labels = bw_tt_categories();
		$map    = array();
		foreach ( $labels as $slug => $label ) {
			$c             = isset( $colors[ $slug ] ) ? $colors[ $slug ] : '#6b7280';
			$map[ $slug ]  = $c;
			$map[ $label ] = $c;
		}
		?>
		<style>
			/* Category shown as a bold heading, not an editable field. */
			.bw-tt-cat-label .acf-label { display: none; }
			.bw-tt-cat-label input[type="text"] {
				border: 0 !important;
				background: transparent !important;
				box-shadow: none !important;
				padding-left: 0 !important;
				font-size: 15px;
				font-weight: 700;
				color: #1d2327;
				pointer-events: none;
			}
			/* Each category row reads as its own colour-coded card. */
			[data-key="field_bwm_tt_panels"] .acf-row {
				margin-bottom: 8px;
				border-left: 5px solid transparent;
			}
			/* Whole collapsed bar + the category heading act as the click target. */
			[data-key="field_bwm_tt_panels"] .acf-row.-collapsed,
			[data-key="field_bwm_tt_panels"] .bw-tt-cat-label {
				cursor: pointer;
			}
		</style>
		<script>
		( function () {
			var MAP = <?php echo wp_json_encode( $map ); // phpcs:ignore WordPress.Security.EscapeOutput ?>;
			var PANELS = '[data-key="field_bwm_tt_panels"]';

			function toggleRow( row ) {
				var t = row.querySelector( '[data-event="collapse-row"]' );
				if ( t ) { t.click(); }
			}

			function decorate() {
				var rows = document.querySelectorAll( PANELS + ' .acf-row:not(.-clone)' );
				rows.forEach( function ( row, idx ) {
					// Colour-code by category.
					var inp = row.querySelector( '[data-key="field_bwm_tt_category"] input' );
					var key = inp ? inp.value.trim() : '';
					var c   = MAP[ key ];
					if ( c ) {
						row.style.borderLeftColor = c;
						row.style.background = c + '12';
					}
					// First category stays open; collapse the rest — via ACF's own
					// toggle so expand/collapse state stays in sync.
					if ( ! row.dataset.bwAccordion ) {
						row.dataset.bwAccordion = '1';
						if ( idx > 0 && ! row.classList.contains( '-collapsed' ) ) {
							toggleRow( row );
						}
					}
				} );
			}

			// Make the category text / collapsed bar the click target (not the
			// little icon on the left). Delegated, bound once.
			function onClick( e ) {
				if ( e.target.closest( '[data-event]' ) ) { return; } // ACF's own buttons handle themselves.
				var row = e.target.closest( PANELS + ' .acf-row' );
				if ( ! row || row.classList.contains( '-clone' ) ) { return; }
				if ( row.classList.contains( '-collapsed' ) ) {
					toggleRow( row ); // Collapsed: clicking the bar opens it.
				} else if ( e.target.closest( '[data-key="field_bwm_tt_category"]' ) ) {
					toggleRow( row ); // Expanded: clicking the category heading closes it.
				}
			}

			function bind() {
				var wrap = document.querySelector( PANELS );
				if ( wrap && ! wrap.dataset.bwBound ) {
					wrap.dataset.bwBound = '1';
					wrap.addEventListener( 'click', onClick );
				}
			}

			function init() { decorate(); bind(); }

			if ( window.acf && typeof acf.addAction === 'function' ) {
				acf.addAction( 'ready', init );
				acf.addAction( 'append', decorate );
			} else if ( document.readyState === 'loading' ) {
				document.addEventListener( 'DOMContentLoaded', init );
			} else {
				init();
			}
		} )();
		</script>
		<?php
	}
);
