<?php

class Customify
{

	static $_instance;
	static $version;
	static $theme_url;
	static $theme_name;
	static $theme_author;
	static $path;

	/**
	 * @var Customify_Customizer
	 */
	public $customizer = null;

	/**
	 * Add functions to hooks
	 */
	function init_hooks()
	{
		add_action('after_setup_theme', array($this, 'theme_setup'));
		add_action('after_setup_theme', array($this, 'content_width'), 0);
		add_action('widgets_init', array($this, 'register_sidebars'));
		add_action('wp_enqueue_scripts', array($this, 'scripts'), 95);
		add_filter('excerpt_more', array($this, 'excerpt_more'));
		add_filter('excerpt_length', array($this, 'excerpt_length'));
		// Font resource hints (preconnect for Google Fonts hosts and a
		// preload for the body font) run at priority 1 — earlier than
		// any stylesheet emission so the browser can start the network
		// work in parallel with CSS parsing. See class-customizer-font-loader.php.
		add_action('wp_head', array($this, 'print_font_resource_hints'), 1);
		add_action('wp_head', array($this, 'customify_style'), 2);
		// Print the palette tokens (:root + Base cascade rules) BEFORE
		// wp_print_styles (priority 8). The composite styling controls
		// (Page bg / Content Area bg / Site Content bg) emit literal
		// `body{background-color:#hex}` via the customify-style-inline-css
		// block at priority 10, AFTER our tokens. That ordering lets:
		//   • Composite-saved sites: literal hex wins by cascade order
		//   • Composite-unsaved sites: composite emits nothing (empty
		//     default → setup_color skips), our var() cascade applies
		// Frontend + customize preview both use this same chain.
		add_action('wp_head', array($this, 'print_palette_tokens'), 8);
	}

	/**
	 * Print the palette :root token block + Base composite cascade rules
	 * BEFORE WP renders enqueued stylesheets. See the docblock above the
	 * `wp_head` priority-8 hook in `init_hooks()` for the cascade-ordering
	 * rationale.
	 *
	 * The id `customify-palette-tokens-inline-css` mirrors WP's inline-style
	 * naming so consumers (frontend, extract_customify_css.py helper) can
	 * find it the same way they find the auto-CSS block.
	 */
	/**
	 * Emit network resource hints for fonts as early as possible in
	 * <head>. Two hints:
	 *   - preconnect to Google Fonts hosts (fonts.googleapis.com +
	 *     fonts.gstatic.com) when any Google font is active — saves
	 *     ~100-300ms TTFB on cold visits.
	 *   - preload for the body font's woff2 file when it's local
	 *     (Theme or Library) — saves ~200-500ms LCP by starting the
	 *     font fetch in parallel with CSS parse.
	 *
	 * Both helpers short-circuit to empty when nothing applies, so
	 * the only cost on pages without fonts is a single class load.
	 */
	function print_font_resource_hints() {
		if ( ! class_exists( 'Customify_Customizer_Font_Loader' ) ) {
			return;
		}
		$out = Customify_Customizer_Font_Loader::preconnect_tags()
			 . Customify_Customizer_Font_Loader::preload_body_font_tag();
		if ( '' === $out ) {
			return;
		}
		echo $out; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped inside builders
	}

	function print_palette_tokens() {
		if ( ! function_exists( 'customify_color_palette_root_css' ) ) {
			return;
		}
		echo "\n<style id='customify-palette-tokens-inline-css'>\n" . customify_color_palette_root_css() . "\n</style>\n";
	}

	function excerpt_length($length)
	{
		return 25;
	}

	/**
	 * Filter the excerpt "read more" string.
	 *
	 * @param string $more "Read more" excerpt string.
	 *
	 * @return string (Maybe) modified "read more" excerpt string.
	 */
	function excerpt_more($more)
	{
		return '&hellip;';
	}

	/**
	 * Main Customify Instance.
	 *
	 * Ensures only one instance of Customify is loaded or can be loaded.
	 *
	 * @return Customify Main instance.
	 */
	static function get_instance()
	{
		if (is_null(self::$_instance)) {
			self::$_instance    = new self();
			$theme              = wp_get_theme();
			self::$version      = $theme->get('Version');
			self::$theme_url    = $theme->get('ThemeURI');
			self::$theme_name   = $theme->get('Name');
			self::$theme_author = $theme->get('Author');
			self::$path         = get_template_directory();

			self::$_instance->init();
		}

		return self::$_instance;
	}

	/**
	 * Get data from method of property
	 *
	 * @param string $key
	 *
	 * @return bool|mixed
	 */
	function get($key)
	{
		if (method_exists($this, 'get_' . $key)) {
			return call_user_func_array(array($this, 'get_' . $key), array());
		} elseif (property_exists($this, $key)) {
			return $this->{$key};
		}

		return false;
	}


	/**
	 * Set the content width in pixels, based on the theme's design and stylesheet.
	 *
	 * Priority 0 to make it available to lower priority callbacks.
	 *
	 * @global int $content_width
	 */
	function content_width()
	{
		$GLOBALS['content_width'] = apply_filters('customify_content_width', 843);
	}

	/**
	 * Sets up theme defaults and registers support for various WordPress features.
	 *
	 * Note that this function is hooked into the after_setup_theme hook, which
	 * runs before the init hook. The init hook is too late for some features, such
	 * as indicating support for post thumbnails.
	 */
	function theme_setup()
	{
		/*
		 * Make theme available for translation.
		 * Translations can be filed in the /languages/ directory.
		 * If you're building a theme based on customify, use a find and replace
		 * to change 'customify' to the name of your theme in all the template files.
		 */
		load_theme_textdomain('customify', get_template_directory() . '/languages');

		// Add default posts and comments RSS feed links to head.
		add_theme_support('automatic-feed-links');

		/*
		 * Let WordPress manage the document title.
		 * By adding theme support, we declare that this theme does not use a
		 * hard-coded <title> tag in the document head, and expect WordPress to
		 * provide it for us.
		 */
		add_theme_support('title-tag');

		/*
		 * Enable support for Post Thumbnails on posts and pages.
		 *
		 * @link https://developer.wordpress.org/themes/functionality/featured-images-post-thumbnails/
		 */
		add_theme_support('post-thumbnails');

		// This theme uses wp_nav_menu() in one location.
		register_nav_menus(
			array(
				'menu-1' => esc_html__('Primary', 'customify'),
			)
		);

		/*
		 * Switch default core markup for search form, comment form, and comments
		 * to output valid HTML5.
		 */
		add_theme_support(
			'html5',
			array(
				'search-form',
				'comment-form',
				'comment-list',
				'gallery',
				'caption',
			)
		);

		// Add theme support for selective refresh for widgets.
		add_theme_support('customize-selective-refresh-widgets');

		// Add theme support for page excerpt.
		add_post_type_support('page', 'excerpt');

		/**
		 * Add support for core custom logo.
		 *
		 * @link https://codex.wordpress.org/Theme_Logo
		 */
		add_theme_support(
			'custom-logo',
			array(
				'height'      => 250,
				'width'       => 250,
				'flex-width'  => true,
				'flex-height' => true,
			)
		);

		/**
		 * WooCommerce support.
		 */
		add_theme_support('woocommerce');
		add_theme_support('wc-product-gallery-zoom');
		add_theme_support('wc-product-gallery-lightbox');
		add_theme_support('wc-product-gallery-slider');

		/**
		 * Support Gutenberg / Block Editor.
		 *
		 * @since 0.2.6
		 * @since 0.4.14 Added responsive-embeds, block-template-parts, editor-color-palette.
		 */
		add_theme_support( 'align-wide' );
		add_theme_support( 'editor-styles' );
		add_theme_support( 'responsive-embeds' );
		add_theme_support( 'block-template-parts' );
		add_theme_support( 'appearance-tools' );
		add_theme_support( 'editor-color-palette',
			array(
				array(
					'name'  => __( 'Primary', 'customify' ),
					'slug'  => 'primary',
					'color' => '#0e7c7b',
				),
				array(
					'name'  => __( 'Secondary', 'customify' ),
					'slug'  => 'secondary',
					'color' => '#c3512f',
				),
				array(
					'name'  => __( 'Text', 'customify' ),
					'slug'  => 'text',
					'color' => '#686868',
				),
				array(
					'name'  => __( 'Link', 'customify' ),
					'slug'  => 'link',
					'color' => '#1e4b75',
				),
				array(
					'name'  => __( 'Light Gray', 'customify' ),
					'slug'  => 'light-gray',
					'color' => '#f2f2f2',
				),
				array(
					'name'  => __( 'Dark Gray', 'customify' ),
					'slug'  => 'dark-gray',
					'color' => '#444444',
				),
			)
		);
	}

	/**
	 * Register sidebars area.
	 *
	 * @link https://developer.wordpress.org/themes/functionality/sidebars/#registering-a-sidebar
	 */
	function register_sidebars()
	{
		register_sidebar(
			array(
				'name'          => esc_html__('Primary Sidebar', 'customify'),
				'id'            => 'sidebar-1',
				'description'   => esc_html__('Add widgets here.', 'customify'),
				'before_widget' => '<section id="%1$s" class="widget %2$s">',
				'after_widget'  => '</section>',
				'before_title'  => '<h4 class="widget-title">',
				'after_title'   => '</h4>',
			)
		);
		register_sidebar(
			array(
				'name'          => esc_html__('Secondary Sidebar', 'customify'),
				'id'            => 'sidebar-2',
				'description'   => esc_html__('Add widgets here.', 'customify'),
				'before_widget' => '<section id="%1$s" class="widget %2$s">',
				'after_widget'  => '</section>',
				'before_title'  => '<h4 class="widget-title">',
				'after_title'   => '</h4>',
			)
		);

		for ($i = 1; $i <= 6; $i++) {
			register_sidebar(
				array(
					/* translators: 1: Widget number. */
					'name'          => sprintf(__('Footer Sidebar %d', 'customify'), $i),
					'id'            => 'footer-' . $i,
					'description'   => __('Add widgets here.', 'customify'),
					'before_widget' => '<section id="%1$s" class="widget %2$s">',
					'after_widget'  => '</section>',
					'before_title'  => '<h4 class="widget-title">',
					'after_title'   => '</h4>',
				)
			);
		}
	}

	/**
	 * Get asset suffix `.min` or empty if WP_DEBUG enabled
	 *
	 * @return string
	 */
	function get_asset_suffix()
	{
		$suffix = '.min';
		if (defined('WP_DEBUG') && WP_DEBUG) {
			$suffix = '';
		}

		return $suffix;
	}

	/**
	 * Enqueue scripts and styles.
	 */
	function scripts()
	{

		if (! class_exists('Customify_Font_Icons')) {
			require_once get_template_directory() . '/inc/customizer/class-customizer-icons.php';
		}
		Customify_Font_Icons::get_instance()->enqueue();

		$suffix = $this->get_asset_suffix();

		do_action('customify/load-scripts');

		$css_files = apply_filters(
			'customify/theme/css',
			array(
				'google-font' => Customify_Customizer_Auto_CSS::get_instance()->get_font_url(),
				'style'       => esc_url(get_template_directory_uri()) . '/build/css/frontend/style-theme' . $suffix . '.css',
			)
		);

		$js_files = apply_filters(
			'customify/theme/js',
			array(
				'customify-themejs' => array(
					'url' => esc_url(get_template_directory_uri()) . '/build/js/frontend/theme' . $suffix . '.js',
					'ver' => self::$version,
				),
			)
		);

		foreach ($css_files as $id => $url) {
			$deps = array();
			if (is_array($url)) {
				$arg = wp_parse_args(
					$url,
					array(
						'deps' => array(),
						'url'  => '',
						'ver'  => self::$version,
					)
				);
				wp_enqueue_style('customify-' . $id, $arg['url'], $arg['deps'], $arg['ver']);
			} elseif ($url) {
				wp_enqueue_style('customify-' . $id, $url, $deps, self::$version);
			}
		}

		foreach ($js_files as $id => $arg) {
			$deps = array();
			$ver  = '';
			if (is_array($arg)) {
				$arg = wp_parse_args(
					$arg,
					array(
						'deps' => '',
						'url'  => '',
						'ver'  => '',
					)
				);

				$deps = $arg['deps'];
				$url  = $arg['url'];
				$ver  = $arg['ver'];
			} else {
				$url = $arg;
			}

			if (! $ver) {
				$ver = self::$version;
			}

			wp_enqueue_script($id, $url, $deps, $ver, true);
		}

		if (is_singular() && comments_open() && get_option('thread_comments')) {
			wp_enqueue_script('comment-reply');
		}

		wp_add_inline_style( 'customify-style', Customify_Customizer_Auto_CSS::get_instance()->auto_css() );
		// Must run AFTER auto_css() — that's where setup_font() populates
		// the theme_fonts / library_fonts buckets from active typography
		// settings. Order doesn't matter between theme/library; both
		// emit standalone @font-face declarations.
		wp_add_inline_style( 'customify-style', Customify_Customizer_Auto_CSS::get_instance()->get_theme_fonts_css() );
		wp_add_inline_style( 'customify-style', Customify_Customizer_Auto_CSS::get_instance()->get_library_fonts_css() );

		// `customify_layout_content_size_css()` ships static body.main-layout-*
		// rules that depend only on the migration-time anchor option, not on
		// any live-tweakable Customizer setting. The Customizer preview JS
		// (src/backend/customizer/js/auto-css.js) rebuilds and OVERWRITES
		// `#customify-style-inline-css` on every setting change, so anything
		// glued onto the main customify-style handle gets wiped — that's how
		// the `narrow_width` slider used to drag content-size down to the
		// theme.json default (863px) on non-narrow pages, reading as "narrow
		// width is being applied everywhere". Hosting the layout CSS in its
		// own inline-only handle keeps the body.main-layout-* rules out of
		// the JS rewrite path. False-source `wp_register_style()` is the
		// canonical WP inline-only pattern (no `<link>` printed, only the
		// `id="customify-layout-style-inline-css"` <style> element).
		wp_register_style( 'customify-layout-style', false, array(), self::$version );
		wp_enqueue_style( 'customify-layout-style' );
		wp_add_inline_style( 'customify-layout-style', customify_layout_content_size_css() );
		// "Post Content Max Width" override: emitted on the SAME handle, AFTER
		// the layout rule, so for a no-sidebar single post `body.single-post`
		// (equal specificity to `body.main-layout-content`) wins by source
		// order. Gated on an explicit save inside the function, so the 30K
		// install base that never touched the slider keeps the layout-derived
		// width; the Customizer live-preview <style> still loads later and wins.
		if ( function_exists( 'customify_single_post_content_size_css' ) ) {
			wp_add_inline_style( 'customify-layout-style', customify_single_post_content_size_css() );
		}
		wp_localize_script(
			'customify-themejs',
			'Customify_JS',
			apply_filters( // phpcs:ignore
				'Customify_JS',
				array(
					'is_rtl'                     => is_rtl(),
					'css_media_queries'          => Customify_Customizer_Auto_CSS::get_instance()->media_queries,
					'sidebar_menu_no_duplicator' => Customify()->get_setting('header_sidebar_menu_no_duplicator'),
				)
			)
		);

		do_action('customify/theme/scripts');
	}

	public function customify_style() {}

	function admin_scripts() {}

	private function includes()
	{
		$files = array(
			'/inc/class-metabox.php',
			// Metabox settings.
			'/inc/template-class.php',
			// Template element classes.
			'/inc/content-area-spacing.php',
			// Context-aware content area vertical spacing.
			'/inc/colors-palette.php',
			// Colors palette CSS var emitter for the new top-level Colors section.
			'/inc/color-palette-switcher.php',
			// Palettes UI (presets + custom palettes) at the top of the Colors section.
			'/inc/color-palette-link.php',
			// PROTOTYPE: palette swatch row inside a component color picker.
			'/inc/style-guide.php',
			// Customizer Style Guide: live specimen page in the preview + header toggle.
			'/inc/extras.php',
			// Custom functions that act independently of the theme templates.
			'/inc/element-classes.php',
			// Functions which enhance the theme by hooking into WordPress and itself (huh?).
			'/inc/template-tags.php',
			// Custom template tags for this theme.
			'/inc/template-functions.php',
			// Functions which enhance the theme by hooking into WordPress.
			'/inc/customizer/class-customizer.php',
			// Customizer additions.
			'/inc/panel-builder/class-panel-builder.php',
			// Panel builder additions.
			'/inc/blog/class-related-posts.php',
			// Blog entry builder.
			'/inc/blog/class-post-entry.php',
			// Blog entry builder.
			'/inc/blog/class-posts-layout.php',
			// Blog posts layout.
			'/inc/blog/functions-posts-layout.php',
			// Search results framework (mixed content cards, type tabs, counts).
			'/inc/search/functions-search.php',
			// Block editor enhancements (block styles, patterns category).
			'/inc/admin/block-styles.php',
			// Block editor Page Settings panel (also registers meta for REST API).
			'/inc/admin/page-settings.php',
			'/inc/admin/dashboard-v2-rest.php',
			// Dashboard v2 REST controller — loads on every request (REST
			// handlers don't run in admin context).
		);

		foreach ($files as $file) {
			require_once self::$path . $file;
		}

		add_action('after_setup_theme', [$this, 'load_configs'], 2);
		add_action('after_setup_theme', [$this, 'load_compatibility'], 2);
		$this->admin_includes();

		// Custom categories walker class.
		if (! is_admin()) {
			require_once self::$path . '/inc/class-categories-walker.php';
		}
	}

	/**
	 * Load admin files
	 *
	 * @since 0.0.1
	 * @since 0.2.6 Load editor style.
	 *
	 * @return void
	 */
	public function admin_includes()
	{
		if (! is_admin()) {
			return;
		}

		$files = array(
			'/inc/admin/editor.php',       // Block editor style integration.
			'/inc/admin/dashboard.php',    // Legacy PHP dashboard (Appearance → Customify Options (Legacy)).
			'/inc/admin/dashboard-v2.php', // New SPA dashboard (top-level Customify) — @pressmaximum/dashboard-kit.
			'/inc/admin/pro-bridge/pro-bridge.php', // Fallback bridge for Customify Pro < 0.4.16 (self-disables on newer Pro).
		);

		foreach ($files as $file) {
			require_once self::$path . $file;
		}

		add_action('admin_enqueue_scripts', array($this, 'admin_scripts'));
	}

	/**
	 * Load configs
	 */
	public function load_configs()
	{

		$config_files = array(
			// Site Settings.
			'upsell',
			'layouts',
			'blogs',
			'single-blog-post',
			'related-posts',

			'search',
			'styling',
			'typography',
			'page-header',
			'background',
			'colors',
			'buttons-forms',
			'compatibility',
			// Header Builder Panel.
			'header/transparent',
			'header/panel',
			'header/html',
			'header/logo',
			'header/nav-icon',
			'header/primary-menu',
			'header/templates',
			'header/templates',
			'header/logo',
			'header/search-icon',
			'header/search-box',
			'header/menus',
			'header/nav-icon',
			'header/button',
			'header/social-icons',
			// Footer Builder Panel.
			'footer/panel',
			'footer/widgets',
			'footer/templates',
			'footer/widgets',
			'footer/copyright',
			'footer/social-icons',

		);

		$path = get_template_directory();
		// Load default config values.
		require_once $path . '/inc/customizer/configs/config-default.php';

		// Load site configs.
		foreach ($config_files as $f) {
			$file = $path . "/inc/customizer/configs/{$f}.php";
			if (file_exists($file)) {
				require_once $file;
			}
		}
	}

	/**
	 * Load site compatibility supports
	 */
	public function load_compatibility()
	{

		$compatibility_config_files = array(
			'customify-pro',     // Disable Pro modules implemented natively by the theme.
			'elementor',         // Plugin breadcrumb-navxt & Yoat Seo.
			'breadcrumb',         // Plugin breadcrumb-navxt & Yoat Seo.
			'woocommerce/woocommerce',  // Plugin WooCommerce.
		);
		foreach ($compatibility_config_files as $f) {
			$file = self::$path . "/inc/compatibility/{$f}.php";
			if (file_exists($file)) {
				require_once $file;
			}
		}
	}

	/**
	 * Check if WooCommerce plugin activated
	 *
	 * @see WooCommerce
	 * @see wc
	 *
	 * @return bool
	 */
	function is_woocommerce_active()
	{
		return class_exists('WooCommerce') || function_exists('wc');
	}

	function is_using_post()
	{
		$use = false;
		if (is_singular()) {
			$use = true;
		} else {
			if (is_front_page() && is_home()) {
				$use = false;
			} elseif (is_front_page()) {
				// static homepage.
				$use = true;
			} elseif (is_home()) {
				// blog page.
				$use = true;
			} else {
				if ($this->is_woocommerce_active()) {
					if (is_shop()) {
						$use = true;
					}
				}
			}
		}

		return $use;
	}

	function is_blog()
	{
		$is_blog = false;
		if (is_front_page() && is_home()) {
			$is_blog = true;
		} elseif (is_front_page()) { //phpcs:ignore
			// static homepage.
		} elseif (is_home()) {
			$is_blog = true;
		}

		return $is_blog;
	}

	function get_current_post_id()
	{
		$id = get_the_ID();
		if (is_front_page() && is_home()) {
			$id = false;
		} elseif (is_front_page()) {
			// Static homepage.
			$id = get_option('page_on_front');
		} elseif (is_home()) {
			// Blog page.
			$id = get_option('page_for_posts');
		} else {
			if ($this->is_woocommerce_active()) {
				if (is_shop()) {
					$id = wc_get_page_id('shop');
				}
			}
		}

		return $id;
	}

	function init()
	{
		$this->init_hooks();
		$this->includes();
		$this->customizer = Customify_Customizer::get_instance();
		$this->customizer->init();
		do_action('customify/init');
	}

	function get_setting($id, $device = 'desktop', $key = null)
	{
		return Customify_Customizer::get_instance()->get_setting($id, $device, $key);
	}

	function get_media($value, $size = null)
	{
		return Customify_Customizer::get_instance()->get_media($value, $size);
	}

	function get_setting_tab($name, $tab = null)
	{
		return Customify_Customizer::get_instance()->get_setting_tab($name, $tab);
	}

	function get_post_types($_builtin = true)
	{
		if ('all' === $_builtin) {
			$post_type_args = array(
				'publicly_queryable' => true,
			);
		} else {
			$post_type_args = array(
				'publicly_queryable' => true,
				'_builtin'           => $_builtin,
			);
		}

		$_post_types = get_post_types($post_type_args, 'objects');

		$post_types = array();

		foreach ($_post_types as $post_type => $object) {
			$post_types[$post_type] = array(
				'name'          => $object->label,
				'singular_name' => $object->labels->singular_name,
			);
		}

		return $post_types;
	}
}
