<?php
/**
 * Admin Sections Registry.
 *
 * @package Noesia_Smart_Waiter
 */

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

if ( ! class_exists( 'Noesia_SWA_Admin_Sections' ) ) {
	/**
	 * Central registry for admin sections and nav items.
	 */
	class Noesia_SWA_Admin_Sections {
		/**
		 * Registered sections.
		 *
		 * @var array<string,array<string,mixed>>
		 */
		protected $sections = array();

		/**
		 * Whether bootstrap registration has run.
		 *
		 * @var bool
		 */
		protected $bootstrapped = false;

		/**
		 * Register a single section.
		 *
		 * @param array<string,mixed> $section Section config.
		 * @return bool
		 */
		public function register_section( array $section ) {
			$defaults = array(
				'id'          => '',
				'label'       => '',
				'nav_label'   => '',
				'nav_sub'     => '',
				'icon'        => '',
				'priority'    => 100,
				'tier'        => 'free',
				'owner'       => 'core',
				'is_visible'  => true,
				'nav_visible' => true,
				'callback'    => null,
			);

			$section = wp_parse_args( $section, $defaults );
			$section['id'] = sanitize_key( (string) $section['id'] );

			if ( '' === $section['id'] ) {
				return false;
			}

			$section['label']       = sanitize_text_field( (string) $section['label'] );
			$section['nav_label']   = sanitize_text_field( (string) $section['nav_label'] );
			$section['nav_sub']     = sanitize_text_field( (string) $section['nav_sub'] );
			$section['icon']        = sanitize_text_field( (string) $section['icon'] );
			$section['priority']    = absint( $section['priority'] );
			$section['tier']        = in_array( $section['tier'], array( 'free', 'pro' ), true ) ? $section['tier'] : 'free';
			$section['owner']       = sanitize_key( (string) $section['owner'] );
			$section['is_visible']  = (bool) $section['is_visible'];
			$section['nav_visible'] = (bool) $section['nav_visible'];

			if ( empty( $section['nav_label'] ) ) {
				$section['nav_label'] = $section['label'];
			}

			$this->sections[ $section['id'] ] = $section;

			return true;
		}

		/**
		 * Register multiple sections.
		 *
		 * @param array<int,array<string,mixed>> $sections Sections.
		 * @return void
		 */
		public function register_sections( array $sections ) {
			foreach ( $sections as $section ) {
				if ( is_array( $section ) ) {
					$this->register_section( $section );
				}
			}
		}

		/**
		 * Bootstrap external registration hooks once.
		 *
		 * @return void
		 */
		public function maybe_bootstrap() {
			if ( $this->bootstrapped ) {
				return;
			}

			$this->bootstrapped = true;

			do_action( 'noesia_swa_register_admin_sections', $this );

			$filtered = apply_filters( 'noesia_swa_admin_sections', array(), $this );
			if ( is_array( $filtered ) ) {
				$this->register_sections( $filtered );
			}

			do_action( 'noesia_swa_admin_sections_loaded', $this );
		}

		/**
		 * Get all sections sorted by priority.
		 *
		 * @return array<string,array<string,mixed>>
		 */
		public function get_sections() {
			$this->maybe_bootstrap();

			$sections = $this->sections;

			uasort(
				$sections,
				static function ( $a, $b ) {
					$ap = isset( $a['priority'] ) ? (int) $a['priority'] : 100;
					$bp = isset( $b['priority'] ) ? (int) $b['priority'] : 100;

					if ( $ap === $bp ) {
						$al = isset( $a['label'] ) ? (string) $a['label'] : '';
						$bl = isset( $b['label'] ) ? (string) $b['label'] : '';
						return strcasecmp( $al, $bl );
					}

					return ( $ap < $bp ) ? -1 : 1;
				}
			);

			return $sections;
		}

		/**
		 * Get visible nav items.
		 *
		 * @return array<string,array<string,mixed>>
		 */
		public function get_nav_items() {
			$items = array();

			foreach ( $this->get_sections() as $id => $section ) {
				if ( empty( $section['nav_visible'] ) || empty( $section['is_visible'] ) ) {
					continue;
				}

				$items[ $id ] = $section;
			}

			return $items;
		}

		/**
		 * Determine whether a section is registered.
		 *
		 * @param string $id Section ID.
		 * @return bool
		 */
		public function has_section( $id ) {
			$id = sanitize_key( (string) $id );

			return '' !== $id && isset( $this->sections[ $id ] );
		}

		/**
		 * Resolve the active section against registry entries.
		 *
		 * @param string $requested Requested slug.
		 * @param string $default   Default slug.
		 * @return string
		 */
		public function resolve_active_section( $requested, $default = 'dashboard' ) {
			$requested = sanitize_key( (string) $requested );
			$default   = sanitize_key( (string) $default );
			$sections  = $this->get_sections();

			if ( '' !== $requested && isset( $sections[ $requested ] ) && ! empty( $sections[ $requested ]['is_visible'] ) ) {
				return $requested;
			}

			if ( isset( $sections[ $default ] ) && ! empty( $sections[ $default ]['is_visible'] ) ) {
				return $default;
			}

			foreach ( $sections as $id => $section ) {
				if ( ! empty( $section['is_visible'] ) ) {
					return $id;
				}
			}

			return $default;
		}

		/**
		 * Get one section.
		 *
		 * @param string $id Section id.
		 * @return array<string,mixed>|null
		 */
		public function get_section( $id ) {
			$id = sanitize_key( (string) $id );
			$sections = $this->get_sections();

			return isset( $sections[ $id ] ) ? $sections[ $id ] : null;
		}

		/**
		 * Render a section by callback.
		 *
		 * @param string $id Section id.
		 * @return void
		 */
		public function render_section( $id ) {
			$section = $this->get_section( $id );

			if ( empty( $section ) || empty( $section['callback'] ) || ! is_callable( $section['callback'] ) ) {
				return;
			}

			call_user_func( $section['callback'], $section, $this );
		}
	}
}
