<?php
/**
 * Widget manager and registration hooks.
 *
 * @package IMPACT_WIDGETS_ELEMENTOR
 */

namespace ImpactAddons\ImpactWidgetsForElementor\Core;

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

final class Widgets_Manager {
	/**
	 * Widget class map.
	 *
	 * @var array<string, string>
	 */
	private static array $widgets = array(
		'advanced-heading'       => 'ImpactAddons\ImpactWidgetsForElementor\\Widgets\\Advanced_Heading',
		'advanced-button'        => 'ImpactAddons\ImpactWidgetsForElementor\\Widgets\\Advanced_Button',
		'iframe-embed'           => 'ImpactAddons\ImpactWidgetsForElementor\\Widgets\\Iframe_Embed',
		'google-map'             => 'ImpactAddons\ImpactWidgetsForElementor\\Widgets\\Google_Map',
		'advanced-accordion'     => 'ImpactAddons\ImpactWidgetsForElementor\\Widgets\\Advanced_Accordion',
		'advanced-tabs'          => 'ImpactAddons\ImpactWidgetsForElementor\\Widgets\\Advanced_Tabs',
		'call-to-action'         => 'ImpactAddons\ImpactWidgetsForElementor\\Widgets\\Call_To_Action',
		'logo-showcase'          => 'ImpactAddons\ImpactWidgetsForElementor\\Widgets\\Logo_Showcase',
		'icon-info-list'         => 'ImpactAddons\ImpactWidgetsForElementor\\Widgets\\Icon_Info_List',
		'post-categories'        => 'ImpactAddons\ImpactWidgetsForElementor\\Widgets\\Post_Categories',
		'post-tags'              => 'ImpactAddons\ImpactWidgetsForElementor\\Widgets\\Post_Tags',
		'related-posts'          => 'ImpactAddons\ImpactWidgetsForElementor\\Widgets\\Related_Posts',
	);

	public static function get_widget_map(): array {
		return self::$widgets;
	}

	public static function get_widget_title( string $slug ): string {
		$map = array(
			'advanced-heading'   => 'Advanced Heading',
			'advanced-button'    => 'Advanced Button',
			'iframe-embed'       => 'Iframe Embed',
			'google-map'         => 'Google Map',
			'advanced-accordion' => 'Advanced Accordion',
			'advanced-tabs'      => 'Advanced Tabs',
			'call-to-action'     => 'Call To Action',
			'logo-showcase'      => 'Logo Showcase',
			'icon-info-list'     => 'Icon / Info List',
			'post-categories'    => 'Post Categories',
			'post-tags'          => 'Post Tags',
			'related-posts'      => 'Related Posts',
		);

		$title = $map[ $slug ] ?? ucwords( str_replace( '-', ' ', $slug ) );

		return function_exists( '__' ) ? __( $title, 'impact-widgets-for-elementor' ) : $title;
	}

	public function __construct() {
		add_action( 'elementor/elements/categories_registered', array( $this, 'register_widget_category' ) );
		add_action( 'elementor/frontend/after_register_styles', array( $this, 'register_frontend_assets' ) );
		add_action( 'elementor/editor/before_enqueue_scripts', array( $this, 'enqueue_editor_assets' ) );
		add_action( 'elementor/widgets/register', array( $this, 'register_widgets' ) );
	}

	private function include_files(): void {
		if ( ! class_exists( '\\Elementor\\Widget_Base' ) ) {
			return;
		}

		require_once IMPACT_WIDGETS_ELEMENTOR_PATH . 'includes/widgets/class-advanced-heading.php';
		require_once IMPACT_WIDGETS_ELEMENTOR_PATH . 'includes/config/class-advanced-button-config.php';
		require_once IMPACT_WIDGETS_ELEMENTOR_PATH . 'includes/widgets/class-advanced-button.php';
		require_once IMPACT_WIDGETS_ELEMENTOR_PATH . 'includes/widgets/class-iframe-embed.php';
		require_once IMPACT_WIDGETS_ELEMENTOR_PATH . 'includes/widgets/class-google-map.php';
		require_once IMPACT_WIDGETS_ELEMENTOR_PATH . 'includes/widgets/class-advanced-nested-accordion.php';
		require_once IMPACT_WIDGETS_ELEMENTOR_PATH . 'includes/widgets/class-advanced-accordion.php';
		require_once IMPACT_WIDGETS_ELEMENTOR_PATH . 'includes/widgets/class-advanced-tabs.php';
		require_once IMPACT_WIDGETS_ELEMENTOR_PATH . 'includes/widgets/class-call-to-action.php';
		require_once IMPACT_WIDGETS_ELEMENTOR_PATH . 'includes/widgets/class-logo-showcase.php';
		require_once IMPACT_WIDGETS_ELEMENTOR_PATH . 'includes/widgets/class-icon-info-list.php';
		require_once IMPACT_WIDGETS_ELEMENTOR_PATH . 'includes/widgets/trait-post-context.php';
		require_once IMPACT_WIDGETS_ELEMENTOR_PATH . 'includes/widgets/class-post-categories.php';
		require_once IMPACT_WIDGETS_ELEMENTOR_PATH . 'includes/widgets/class-post-tags.php';
		require_once IMPACT_WIDGETS_ELEMENTOR_PATH . 'includes/widgets/class-related-posts.php';
	}

	public function register_widget_category( $elements_manager ): void {
		$category_data = array(
			'title' => esc_html__( 'Impact Widgets for Elementor', 'impact-widgets-for-elementor' ),
			'icon'  => 'fa fa-plug',
		);

		$elements_manager->add_category( 'impact-widgets-elementor', $category_data );

		$this->move_category_after_basic( $elements_manager, 'impact-widgets-elementor' );
	}

	/**
	 * Move a category right after the Elementor "basic" category.
	 *
	 * Elementor versions with no positional add_category API append custom
	 * categories near the bottom. This keeps IMPACT_WIDGETS_ELEMENTOR near core widgets.
	 *
	 * @param object $elements_manager Elementor elements manager.
	 * @param string $category_slug    Category slug to move.
	 */
	private function move_category_after_basic( $elements_manager, string $category_slug ): void {
		if ( ! method_exists( $elements_manager, 'get_categories' ) ) {
			return;
		}

		$categories = $elements_manager->get_categories();

		if ( ! isset( $categories[ $category_slug ], $categories['basic'] ) ) {
			return;
		}

		$target_category = $categories[ $category_slug ];
		unset( $categories[ $category_slug ] );

		$ordered_categories = array();

		foreach ( $categories as $slug => $data ) {
			$ordered_categories[ $slug ] = $data;

			if ( 'basic' === $slug ) {
				$ordered_categories[ $category_slug ] = $target_category;
			}
		}

		// Fallback: if "basic" is missing for any reason, keep category available.
		if ( ! isset( $ordered_categories[ $category_slug ] ) ) {
			$ordered_categories[ $category_slug ] = $target_category;
		}

		try {
			$reflection = new \ReflectionObject( $elements_manager );
			$property   = $reflection->getProperty( 'categories' );
			$property->setAccessible( true );
			$property->setValue( $elements_manager, $ordered_categories );
		} catch ( \ReflectionException $e ) {
			// Do nothing; fallback order is still functional.
		}
	}

	public function register_frontend_assets(): void {
		wp_register_style(
			'impact_widgets_elementor_advanced-heading',
			IMPACT_WIDGETS_ELEMENTOR_URL . 'assets/css/advanced-heading.css',
			array(),
			IMPACT_WIDGETS_ELEMENTOR_VERSION
		);

		wp_register_style(
			'impact_widgets_elementor_advanced-button',
			IMPACT_WIDGETS_ELEMENTOR_URL . 'assets/css/advanced-button.css',
			array(),
			IMPACT_WIDGETS_ELEMENTOR_VERSION
		);

		wp_register_style(
			'impact_widgets_elementor_iframe-embed',
			IMPACT_WIDGETS_ELEMENTOR_URL . 'assets/css/iframe-embed.css',
			array(),
			$this->asset_version( 'assets/css/iframe-embed.css' )
		);

		wp_register_style(
			'impact_widgets_elementor_google-map',
			IMPACT_WIDGETS_ELEMENTOR_URL . 'assets/css/google-map.css',
			array(),
			$this->asset_version( 'assets/css/google-map.css' )
		);

		wp_register_style(
			'impact_widgets_elementor_advanced-nested-accordion',
			IMPACT_WIDGETS_ELEMENTOR_URL . 'assets/css/advanced-nested-accordion.css',
			array(),
			$this->asset_version( 'assets/css/advanced-nested-accordion.css' )
		);

		wp_register_style(
			'impact_widgets_elementor_advanced-tabs',
			IMPACT_WIDGETS_ELEMENTOR_URL . 'assets/css/advanced-tabs.css',
			array(),
			$this->asset_version( 'assets/css/advanced-tabs.css' )
		);

		wp_register_style(
			'impact_widgets_elementor_call-to-action',
			IMPACT_WIDGETS_ELEMENTOR_URL . 'assets/css/call-to-action.css',
			array(),
			$this->asset_version( 'assets/css/call-to-action.css' )
		);

		wp_register_style(
			'impact_widgets_elementor_logo-showcase',
			IMPACT_WIDGETS_ELEMENTOR_URL . 'assets/css/logo-showcase.css',
			array(),
			$this->asset_version( 'assets/css/logo-showcase.css' )
		);

		wp_register_style(
			'impact_widgets_elementor_icon-info-list',
			IMPACT_WIDGETS_ELEMENTOR_URL . 'assets/css/icon-info-list.css',
			array(),
			IMPACT_WIDGETS_ELEMENTOR_VERSION
		);

		wp_register_style(
			'impact_widgets_elementor_post-widgets',
			IMPACT_WIDGETS_ELEMENTOR_URL . 'assets/css/post-widgets.css',
			array(),
			$this->asset_version( 'assets/css/post-widgets.css' )
		);

		wp_register_script(
			'impact_widgets_elementor_google-map',
			IMPACT_WIDGETS_ELEMENTOR_URL . 'assets/js/google-map.js',
			array( 'elementor-frontend' ),
			$this->asset_version( 'assets/js/google-map.js' ),
			true
		);

		wp_register_script(
			'impact_widgets_elementor_advanced-nested-accordion',
			IMPACT_WIDGETS_ELEMENTOR_URL . 'assets/js/advanced-nested-accordion.js',
			array( 'elementor-frontend' ),
			$this->asset_version( 'assets/js/advanced-nested-accordion.js' ),
			true
		);

		wp_register_script(
			'impact_widgets_elementor_advanced-tabs',
			IMPACT_WIDGETS_ELEMENTOR_URL . 'assets/js/advanced-tabs.js',
			array( 'elementor-frontend' ),
			$this->asset_version( 'assets/js/advanced-tabs.js' ),
			true
		);

		wp_register_script(
			'impact_widgets_elementor_logo-showcase',
			IMPACT_WIDGETS_ELEMENTOR_URL . 'assets/js/logo-showcase.js',
			array( 'elementor-frontend' ),
			$this->asset_version( 'assets/js/logo-showcase.js' ),
			true
		);
	}

	public function register_widgets( $widgets_manager ): void {
		$this->include_files();

		foreach ( self::get_widget_map() as $widget_class ) {
			if ( class_exists( $widget_class ) ) {
				$widgets_manager->register( new $widget_class() );
			}
		}
	}

	public function enqueue_editor_assets(): void {
		wp_enqueue_script(
			'impact_widgets_elementor_advanced-tabs-editor',
			IMPACT_WIDGETS_ELEMENTOR_URL . 'assets/js/advanced-tabs-editor.js',
			array( 'jquery', 'elementor-editor', 'nested-elements', 'nested-tabs' ),
			$this->asset_version( 'assets/js/advanced-tabs-editor.js' ),
			true
		);

		wp_enqueue_script(
			'impact_widgets_elementor_advanced-accordion-editor',
			IMPACT_WIDGETS_ELEMENTOR_URL . 'assets/js/advanced-accordion-editor.js',
			array( 'jquery', 'elementor-editor', 'nested-elements', 'nested-accordion' ),
			$this->asset_version( 'assets/js/advanced-accordion-editor.js' ),
			true
		);
	}

	private function asset_version( string $relative_path ): string {
		$file = IMPACT_WIDGETS_ELEMENTOR_PATH . ltrim( $relative_path, '/\\' );

		if ( file_exists( $file ) ) {
			$modified = filemtime( $file );
			if ( false !== $modified ) {
				return (string) $modified;
			}
		}

		return IMPACT_WIDGETS_ELEMENTOR_VERSION;
	}
}
