<?php
/**
 * Widget Name: Advanced Progress Bar
 * Description: A multi-bar progress / skill widget with selectable visual styles,
 *              including line, striped, inline, segmented and circular variants.
 *              Each bar has its own title, value, optional icon and colour. Values
 *              count up and fill when scrolled into view ( with a configurable
 *              duration ). Only the selected style CSS file is loaded on the
 *              frontend.
 *
 * @package    captain-widgets-kit
 * @subpackage captain-widgets-kit/includes
 * @since      1.6.0
 */

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

use Elementor\Widget_Base;
use Elementor\Controls_Manager;
use Elementor\Repeater;
use Elementor\Group_Control_Typography;
use Elementor\Icons_Manager;

/**
 * Class Captwiki_Progress_Bar
 *
 * @since 1.6.0
 */
class Captwiki_Progress_Bar extends Widget_Base {

	/**
	 * Get widget name.
	 *
	 * @since 1.6.0
	 * @return string
	 */
	public function get_name(): string {
		return 'captwiki-progress-bar';
	}

	/**
	 * Get widget title.
	 *
	 * @since 1.6.0
	 * @return string
	 */
	public function get_title(): string {
		return esc_html__( 'Advanced Progress Bar', 'captain-widgets-kit' );
	}

	/**
	 * Get widget icon.
	 *
	 * @since 1.6.0
	 * @return string
	 */
	public function get_icon(): string {
		return 'eicon-skill-bar captwiki-el-logo';
	}

	/**
	 * Get widget categories.
	 *
	 * @since 1.6.0
	 * @return array
	 */
	public function get_categories(): array {
		return array( 'captwiki-essential' );
	}

	/**
	 * Get widget keywords.
	 *
	 * @since 1.6.0
	 * @return array
	 */
	public function get_keywords(): array {
		return array( 'progress', 'bar', 'skill', 'percentage', 'meter', 'circular', 'loader', 'captain-widgets-kit' );
	}

	/**
	 * Frontend script dependency.
	 *
	 * @since 1.6.0
	 * @return array
	 */
	public function get_script_depends(): array {
		return array( 'captwiki-progress-bar' );
	}

	/**
	 * Common stylesheet dependency.
	 *
	 * @since 1.6.0
	 * @return array
	 */
	public function get_style_depends(): array {
		return array( 'captwiki_progress_bar' );
	}

	/**
	 * Disable Elementor's default inner wrapper.
	 *
	 * @since 1.6.0
	 * @return bool
	 */
	public function has_widget_inner_wrapper(): bool {
		return ! \Elementor\Plugin::$instance->experiments->is_feature_active( 'e_optimized_markup' );
	}

	/**
	 * Selectable visual styles.
	 *
	 * @since 1.6.0
	 * @return array
	 */
	private function captwiki_style_options(): array {
		return array(
			'style-1' => esc_html__( 'Style 1 – Classic Line', 'captain-widgets-kit' ),
			'style-2' => esc_html__( 'Style 2 – Animated Stripes', 'captain-widgets-kit' ),
			'style-3' => esc_html__( 'Style 3 – Inline Gradient', 'captain-widgets-kit' ),
			'style-4' => esc_html__( 'Style 4 – Segmented', 'captain-widgets-kit' ),
			'style-5' => esc_html__( 'Style 5 – Circular', 'captain-widgets-kit' ),
		);
	}

	/**
	 * Whether the given style renders as a circular meter.
	 *
	 * @since 1.6.0
	 * @param string $style Style key.
	 * @return bool
	 */
	private function captwiki_is_circular( string $style ): bool {
		return 'style-5' === $style;
	}

	/**
	 * Register widget controls.
	 *
	 * @since 1.6.0
	 * @return void
	 */
	protected function register_controls(): void {
		$this->register_bars_controls();
		$this->register_settings_controls();

		$this->register_general_style_controls();
		$this->register_title_style_controls();
		$this->register_percent_style_controls();
		$this->register_bar_style_controls();
		$this->register_circle_style_controls();
	}

	/**
	 * Content tab — bars.
	 *
	 * @since 1.6.0
	 * @return void
	 */
	private function register_bars_controls(): void {

		$this->start_controls_section(
			'section_bars',
			array(
				'label' => esc_html__( 'Bars', 'captain-widgets-kit' ),
				'tab'   => Controls_Manager::TAB_CONTENT,
			)
		);

		$this->add_control(
			'widget_style',
			array(
				'label'   => esc_html__( 'Style', 'captain-widgets-kit' ),
				'type'    => Controls_Manager::SELECT,
				'default' => 'style-1',
				'options' => $this->captwiki_style_options(),
			)
		);

		$repeater = new Repeater();

		$repeater->add_control(
			'bar_title',
			array(
				'label'       => esc_html__( 'Title', 'captain-widgets-kit' ),
				'type'        => Controls_Manager::TEXT,
				'default'     => esc_html__( 'Skill', 'captain-widgets-kit' ),
				'label_block' => true,
				'dynamic'     => array( 'active' => true ),
			)
		);

		$repeater->add_control(
			'bar_value',
			array(
				'label'   => esc_html__( 'Value (%)', 'captain-widgets-kit' ),
				'type'    => Controls_Manager::NUMBER,
				'min'     => 0,
				'max'     => 100,
				'step'    => 1,
				'default' => 80,
			)
		);

		$repeater->add_control(
			'bar_icon',
			array(
				'label'       => esc_html__( 'Icon', 'captain-widgets-kit' ),
				'type'        => Controls_Manager::ICONS,
				'skin'        => 'inline',
				'label_block' => false,
			)
		);

		$repeater->add_control(
			'bar_color',
			array(
				'label'     => esc_html__( 'Fill Color', 'captain-widgets-kit' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '',
				'selectors' => array(
					'{{WRAPPER}} {{CURRENT_ITEM}}' => '--captwiki-pb-accent: {{VALUE}};',
				),
			)
		);

		$repeater->add_control(
			'bar_color_2',
			array(
				'label'     => esc_html__( 'Fill Color – Second', 'captain-widgets-kit' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '',
				'selectors' => array(
					'{{WRAPPER}} {{CURRENT_ITEM}}' => '--captwiki-pb-accent-2: {{VALUE}};',
				),
				'description' => esc_html__( 'Optional second stop for gradient fills.', 'captain-widgets-kit' ),
			)
		);

		$this->add_control(
			'bars',
			array(
				'label'       => esc_html__( 'Bars', 'captain-widgets-kit' ),
				'type'        => Controls_Manager::REPEATER,
				'fields'      => $repeater->get_controls(),
				'default'     => array(
					array(
						'bar_title' => esc_html__( 'Web Design', 'captain-widgets-kit' ),
						'bar_value' => 90,
					),
					array(
						'bar_title' => esc_html__( 'Development', 'captain-widgets-kit' ),
						'bar_value' => 75,
					),
					array(
						'bar_title' => esc_html__( 'Marketing', 'captain-widgets-kit' ),
						'bar_value' => 60,
					),
				),
				'title_field' => '{{{ bar_title }}} ({{{ bar_value }}}%)',
			)
		);

		$this->end_controls_section();
	}

	/**
	 * Content tab — behaviour settings.
	 *
	 * @since 1.6.0
	 * @return void
	 */
	private function register_settings_controls(): void {

		$this->start_controls_section(
			'section_settings',
			array(
				'label' => esc_html__( 'Settings', 'captain-widgets-kit' ),
				'tab'   => Controls_Manager::TAB_CONTENT,
			)
		);

		$this->add_control(
			'show_percent',
			array(
				'label'        => esc_html__( 'Show Percentage', 'captain-widgets-kit' ),
				'type'         => Controls_Manager::SWITCHER,
				'label_on'     => esc_html__( 'Show', 'captain-widgets-kit' ),
				'label_off'    => esc_html__( 'Hide', 'captain-widgets-kit' ),
				'return_value' => 'yes',
				'default'      => 'yes',
			)
		);

		$this->add_control(
			'percent_suffix',
			array(
				'label'     => esc_html__( 'Percentage Suffix', 'captain-widgets-kit' ),
				'type'      => Controls_Manager::TEXT,
				'default'   => '%',
				'condition' => array( 'show_percent' => 'yes' ),
			)
		);

		$this->add_control(
			'animate',
			array(
				'label'        => esc_html__( 'Animate on Scroll', 'captain-widgets-kit' ),
				'type'         => Controls_Manager::SWITCHER,
				'label_on'     => esc_html__( 'Yes', 'captain-widgets-kit' ),
				'label_off'    => esc_html__( 'No', 'captain-widgets-kit' ),
				'return_value' => 'yes',
				'default'      => 'yes',
			)
		);

		$this->add_control(
			'animation_duration',
			array(
				'label'      => esc_html__( 'Animation Duration', 'captain-widgets-kit' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'ms' ),
				'range'      => array(
					'ms' => array(
						'min'  => 300,
						'max'  => 4000,
						'step' => 100,
					),
				),
				'default'    => array(
					'unit' => 'ms',
					'size' => 1500,
				),
				'condition'  => array( 'animate' => 'yes' ),
			)
		);

		$this->end_controls_section();
	}

	/**
	 * Style tab — general.
	 *
	 * @since 1.6.0
	 * @return void
	 */
	private function register_general_style_controls(): void {

		$this->start_controls_section(
			'section_general_style',
			array(
				'label' => esc_html__( 'General', 'captain-widgets-kit' ),
				'tab'   => Controls_Manager::TAB_STYLE,
			)
		);

		$this->add_control(
			'accent_color',
			array(
				'label'       => esc_html__( 'Accent Color', 'captain-widgets-kit' ),
				'type'        => Controls_Manager::COLOR,
				'default'     => '',
				'selectors'   => array(
					'{{WRAPPER}} .captwiki-progress' => '--captwiki-pb-accent: {{VALUE}};',
				),
				'description' => esc_html__( 'Default fill colour ( per-bar colour overrides this ).', 'captain-widgets-kit' ),
			)
		);

		$this->add_control(
			'accent_color_2',
			array(
				'label'     => esc_html__( 'Accent Color – Second', 'captain-widgets-kit' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '',
				'selectors' => array(
					'{{WRAPPER}} .captwiki-progress' => '--captwiki-pb-accent-2: {{VALUE}};',
				),
			)
		);

		$this->add_control(
			'track_color',
			array(
				'label'     => esc_html__( 'Track Color', 'captain-widgets-kit' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '',
				'selectors' => array(
					'{{WRAPPER}} .captwiki-progress' => '--captwiki-pb-track: {{VALUE}};',
				),
			)
		);

		$this->add_responsive_control(
			'bars_gap',
			array(
				'label'      => esc_html__( 'Gap Between Bars', 'captain-widgets-kit' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px', 'em' ),
				'range'      => array(
					'px' => array(
						'min' => 4,
						'max' => 80,
					),
				),
				'selectors'  => array(
					'{{WRAPPER}} .captwiki-progress' => 'gap: {{SIZE}}{{UNIT}};',
				),
			)
		);

		$this->add_responsive_control(
			'content_align',
			array(
				'label'     => esc_html__( 'Circular Alignment', 'captain-widgets-kit' ),
				'type'      => Controls_Manager::CHOOSE,
				'default'   => 'center',
				'options'   => array(
					'flex-start' => array(
						'title' => esc_html__( 'Left', 'captain-widgets-kit' ),
						'icon'  => 'eicon-text-align-left',
					),
					'center'     => array(
						'title' => esc_html__( 'Center', 'captain-widgets-kit' ),
						'icon'  => 'eicon-text-align-center',
					),
					'flex-end'   => array(
						'title' => esc_html__( 'Right', 'captain-widgets-kit' ),
						'icon'  => 'eicon-text-align-right',
					),
				),
				'selectors' => array(
					'{{WRAPPER}} .captwiki-progress--circular' => 'justify-content: {{VALUE}};',
				),
				'condition' => array( 'widget_style' => 'style-5' ),
			)
		);

		$this->end_controls_section();
	}

	/**
	 * Style tab — title.
	 *
	 * @since 1.6.0
	 * @return void
	 */
	private function register_title_style_controls(): void {

		$this->start_controls_section(
			'section_title_style',
			array(
				'label' => esc_html__( 'Title', 'captain-widgets-kit' ),
				'tab'   => Controls_Manager::TAB_STYLE,
			)
		);

		$this->add_control(
			'title_color',
			array(
				'label'     => esc_html__( 'Color', 'captain-widgets-kit' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '',
				'selectors' => array(
					'{{WRAPPER}} .captwiki-progress__label'     => 'color: {{VALUE}};',
					'{{WRAPPER}} .captwiki-progress__label svg' => 'fill: {{VALUE}};',
				),
			)
		);

		$this->add_group_control(
			Group_Control_Typography::get_type(),
			array(
				'name'     => 'title_typography',
				'selector' => '{{WRAPPER}} .captwiki-progress__label',
			)
		);

		$this->end_controls_section();
	}

	/**
	 * Style tab — percentage.
	 *
	 * @since 1.6.0
	 * @return void
	 */
	private function register_percent_style_controls(): void {

		$this->start_controls_section(
			'section_percent_style',
			array(
				'label'     => esc_html__( 'Percentage', 'captain-widgets-kit' ),
				'tab'       => Controls_Manager::TAB_STYLE,
				'condition' => array( 'show_percent' => 'yes' ),
			)
		);

		$this->add_control(
			'percent_color',
			array(
				'label'     => esc_html__( 'Color', 'captain-widgets-kit' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '',
				'selectors' => array(
					'{{WRAPPER}} .captwiki-progress__percent' => 'color: {{VALUE}};',
				),
			)
		);

		$this->add_group_control(
			Group_Control_Typography::get_type(),
			array(
				'name'     => 'percent_typography',
				'selector' => '{{WRAPPER}} .captwiki-progress__percent',
			)
		);

		$this->end_controls_section();
	}

	/**
	 * Style tab — bar ( linear ).
	 *
	 * @since 1.6.0
	 * @return void
	 */
	private function register_bar_style_controls(): void {

		$this->start_controls_section(
			'section_bar_style',
			array(
				'label'     => esc_html__( 'Bar', 'captain-widgets-kit' ),
				'tab'       => Controls_Manager::TAB_STYLE,
				'condition' => array( 'widget_style!' => 'style-5' ),
			)
		);

		$this->add_responsive_control(
			'bar_height',
			array(
				'label'      => esc_html__( 'Height', 'captain-widgets-kit' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px' ),
				'range'      => array(
					'px' => array(
						'min' => 4,
						'max' => 60,
					),
				),
				'selectors'  => array(
					'{{WRAPPER}} .captwiki-progress' => '--captwiki-pb-height: {{SIZE}}{{UNIT}};',
				),
			)
		);

		$this->add_responsive_control(
			'bar_radius',
			array(
				'label'      => esc_html__( 'Border Radius', 'captain-widgets-kit' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px', '%' ),
				'range'      => array(
					'px' => array(
						'min' => 0,
						'max' => 40,
					),
				),
				'selectors'  => array(
					'{{WRAPPER}} .captwiki-progress__track' => 'border-radius: {{SIZE}}{{UNIT}};',
					'{{WRAPPER}} .captwiki-progress__fill'  => 'border-radius: {{SIZE}}{{UNIT}};',
				),
			)
		);

		$this->add_responsive_control(
			'segment_count',
			array(
				'label'      => esc_html__( 'Segment Count', 'captain-widgets-kit' ),
				'type'       => Controls_Manager::SLIDER,
				'range'      => array(
					'px' => array(
						'min' => 5,
						'max' => 50,
					),
				),
				'default'    => array(
					'size' => 20,
				),
				'selectors'  => array(
					'{{WRAPPER}} .captwiki-progress' => '--captwiki-pb-segments: {{SIZE}};',
				),
				'condition'  => array( 'widget_style' => 'style-4' ),
				'description' => esc_html__( 'Number of blocks in the Segmented style.', 'captain-widgets-kit' ),
			)
		);

		$this->end_controls_section();
	}

	/**
	 * Style tab — circle ( circular meter ).
	 *
	 * @since 1.6.0
	 * @return void
	 */
	private function register_circle_style_controls(): void {

		$this->start_controls_section(
			'section_circle_style',
			array(
				'label'     => esc_html__( 'Circle', 'captain-widgets-kit' ),
				'tab'       => Controls_Manager::TAB_STYLE,
				'condition' => array( 'widget_style' => 'style-5' ),
			)
		);

		$this->add_responsive_control(
			'circle_size',
			array(
				'label'      => esc_html__( 'Size', 'captain-widgets-kit' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px' ),
				'range'      => array(
					'px' => array(
						'min' => 80,
						'max' => 320,
					),
				),
				'selectors'  => array(
					'{{WRAPPER}} .captwiki-progress' => '--captwiki-pb-csize: {{SIZE}}{{UNIT}};',
				),
			)
		);

		$this->add_responsive_control(
			'circle_thickness',
			array(
				'label'      => esc_html__( 'Thickness', 'captain-widgets-kit' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px' ),
				'range'      => array(
					'px' => array(
						'min' => 3,
						'max' => 40,
					),
				),
				'selectors'  => array(
					'{{WRAPPER}} .captwiki-progress' => '--captwiki-pb-thick: {{SIZE}}{{UNIT}};',
				),
			)
		);

		$this->add_responsive_control(
			'circle_gap',
			array(
				'label'      => esc_html__( 'Columns Gap', 'captain-widgets-kit' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px' ),
				'range'      => array(
					'px' => array(
						'min' => 8,
						'max' => 80,
					),
				),
				'selectors'  => array(
					'{{WRAPPER}} .captwiki-progress--circular' => 'gap: {{SIZE}}{{UNIT}};',
				),
			)
		);

		$this->end_controls_section();
	}

	/**
	 * Capture an Elementor icon as an HTML string.
	 *
	 * @since 1.6.0
	 * @param array $icon Icon control value.
	 * @return string
	 */
	private function captwiki_get_icon_html( array $icon ): string {
		ob_start();
		Icons_Manager::render_icon( $icon, array( 'aria-hidden' => 'true' ) );
		return (string) ob_get_clean();
	}

	/**
	 * Render the head row ( label + percentage ) for a linear bar.
	 *
	 * @since 1.6.0
	 * @param array  $bar      Repeater item.
	 * @param string $title    Sanitised title.
	 * @param int    $value    Clamped value.
	 * @param array  $settings Widget settings.
	 * @return void
	 */
	private function captwiki_render_head( array $bar, string $title, int $value, array $settings ): void {
		echo '<div class="captwiki-progress__head">';

		echo '<span class="captwiki-progress__label">';

		if ( ! empty( $bar['bar_icon']['value'] ) ) {
			echo '<span class="captwiki-progress__icon" aria-hidden="true">' . $this->captwiki_get_icon_html( $bar['bar_icon'] ) . '</span>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		}

		echo '<span class="captwiki-progress__label-text">' . esc_html( $title ) . '</span>';
		echo '</span>';

		if ( 'yes' === $settings['show_percent'] ) {
			printf(
				'<span class="captwiki-progress__percent" data-value="%1$d" data-suffix="%2$s">0%2$s</span>',
				esc_attr( $value ),
				esc_attr( (string) $settings['percent_suffix'] )
			);
		}

		echo '</div>';
	}

	/**
	 * Render widget output on the frontend.
	 *
	 * @since 1.6.0
	 * @return void
	 */
	protected function render(): void {
		$settings = $this->get_settings_for_display();

		if ( empty( $settings['bars'] ) || ! is_array( $settings['bars'] ) ) {
			return;
		}

		$allowed_styles = array_keys( $this->captwiki_style_options() );
		$style          = in_array( $settings['widget_style'], $allowed_styles, true ) ? $settings['widget_style'] : 'style-1';

		// Load only the active style stylesheet, depending on the common one.
		wp_enqueue_style(
			'captwiki-progress-bar-' . $style,
			CAPTWIKI_URL . 'assets/css/widgets/progress-bar/captwiki-progress-bar-' . $style . '.css',
			array( 'captwiki_progress_bar' ),
			CAPTWIKI_VERSION
		);

		$is_circular = $this->captwiki_is_circular( $style );
		$animate     = 'yes' === $settings['animate'] ? 'yes' : 'no';
		$duration    = isset( $settings['animation_duration']['size'] ) ? absint( $settings['animation_duration']['size'] ) : 1500;
		$duration    = $duration > 0 ? $duration : 1500;
		$layout      = $is_circular ? ' captwiki-progress--circular' : ' captwiki-progress--linear';

		printf(
			'<div class="captwiki-progress captwiki-%1$s%2$s" data-animate="%3$s" data-duration="%4$d">',
			esc_attr( $style ),
			esc_attr( $layout ),
			esc_attr( $animate ),
			esc_attr( $duration )
		);

		foreach ( $settings['bars'] as $bar ) {
			$bar      = (array) $bar;
			$title    = isset( $bar['bar_title'] ) ? trim( (string) $bar['bar_title'] ) : '';
			$value    = isset( $bar['bar_value'] ) ? (int) $bar['bar_value'] : 0;
			$value    = max( 0, min( 100, $value ) );
			$item_id  = ! empty( $bar['_id'] ) ? 'elementor-repeater-item-' . sanitize_html_class( $bar['_id'] ) : '';
			$suffix   = (string) $settings['percent_suffix'];

			if ( $is_circular ) {
				printf(
					'<div class="captwiki-progress__item captwiki-progress__item--circle %1$s" data-value="%2$d">',
					esc_attr( $item_id ),
					esc_attr( $value )
				);

				echo '<div class="captwiki-progress__circle-wrap">';
				printf( '<div class="captwiki-progress__circle" data-value="%1$d" style="--captwiki-pb-p:0;"></div>', esc_attr( $value ) );
				echo '<div class="captwiki-progress__circle-content">';

				if ( ! empty( $bar['bar_icon']['value'] ) ) {
					echo '<span class="captwiki-progress__icon" aria-hidden="true">' . $this->captwiki_get_icon_html( $bar['bar_icon'] ) . '</span>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
				}

				if ( 'yes' === $settings['show_percent'] ) {
					printf(
						'<span class="captwiki-progress__percent" data-value="%1$d" data-suffix="%2$s">0%2$s</span>',
						esc_attr( $value ),
						esc_attr( $suffix )
					);
				}

				echo '</div>'; // content.
				echo '</div>'; // circle-wrap.

				if ( '' !== $title ) {
					echo '<span class="captwiki-progress__label"><span class="captwiki-progress__label-text">' . esc_html( $title ) . '</span></span>';
				}

				echo '</div>'; // item.
				continue;
			}

			// Linear styles.
			printf(
				'<div class="captwiki-progress__item %1$s" data-value="%2$d">',
				esc_attr( $item_id ),
				esc_attr( $value )
			);

			$this->captwiki_render_head( $bar, $title, $value, $settings );

			echo '<div class="captwiki-progress__track">';
			printf(
				'<div class="captwiki-progress__fill" data-value="%1$d" style="width:0;"><span class="captwiki-progress__fill-glow" aria-hidden="true"></span></div>',
				esc_attr( $value )
			);
			echo '</div>';

			echo '</div>'; // item.
		}

		echo '</div>'; // progress.
	}
}
