<?php
/**
 * Class: Jet_Elements_Weather
 * Name: Weather
 * Slug: jet-weather
 */

namespace Elementor;

use Elementor\Controls_Manager;
use Elementor\Group_Control_Border;
use Elementor\Group_Control_Box_Shadow;
use Elementor\Group_Control_Typography;
use Elementor\Repeater;
use Elementor\Widget_Base;

if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

class Jet_Elements_Weather extends Jet_Elements_Base {

	public $weather_data = array();

	/**
	 * API count
	 *
	 * 1.0 Used Yahoo API
	 * 2.0 Used APIXU API
	 * 3.0 Use Weatherbit.io API
	 *
	 * @var string
	 */
	private $api_count = '3.0';

	private $current_weather_api_url = 'https://api.weatherbit.io/v2.0/current';
	private $forecast_weather_api_url = 'https://api.weatherbit.io/v2.0/forecast/daily';
	private $owm_current_url  = 'https://api.openweathermap.org/data/2.5/weather';
	private $owm_forecast_url = 'https://api.openweathermap.org/data/2.5/forecast';

	public function get_name() {
		return 'jet-weather';
	}

	public function get_title() {
		return esc_html__( 'Weather', 'jet-elements' );
	}

	public function get_icon() {
		return 'jet-elements-icon-weather';
	}

	public function get_jet_help_url() {
		return 'https://crocoblock.com/knowledge-base/articles/jetelements-weather-widget-how-to-display-current-weather-and-forecast/';
	}

	public function get_categories() {
		return array( 'cherry' );
	}

	protected function is_dynamic_content(): bool {
		return false;
	}

	public function get_style_depends() { 
		return array( 'jet-weather' ); 
	}

	protected function register_controls() {
		$css_scheme = apply_filters(
			'jet-elements/weather/css-scheme',
			array(
				'title'                 => '.jet-weather__title',
				'current_container'     => '.jet-weather__current',
				'current_temp'          => '.jet-weather__current-temp',
				'current_icon'          => '.jet-weather__current-icon .jet-weather-icon',
				'current_desc'          => '.jet-weather__current-desc',
				'current_details'       => '.jet-weather__details',
				'current_details_item'  => '.jet-weather__details-item',
				'current_details_icon'  => '.jet-weather__details-item .jet-weather-icon',
				'current_day'           => '.jet-weather__current-day',
				'forecast_container'    => '.jet-weather__forecast',
				'forecast_item'         => '.jet-weather__forecast-item',
				'forecast_day'          => '.jet-weather__forecast-day',
				'forecast_icon'         => '.jet-weather__forecast-icon .jet-weather-icon',
			)
		);

		$this->start_controls_section(
			'section_weather',
			array(
				'label' => esc_html__( 'Weather', 'jet-elements' ),
			)
		);

		$api_key = jet_elements_settings()->get( 'weather_api_key' );
		$openweathermap_api_key = jet_elements_settings()->get( 'openweathermap_api_key' );

		$this->add_control(
			'weather_api_provider',
			array(
				'label'   => esc_html__( 'Weather API Provider', 'jet-elements' ),
				'type'    => Controls_Manager::SELECT,
				'default' => 'weatherbit',
				'options' => array(
					'weatherbit'     => esc_html__( 'Weatherbit (default)', 'jet-elements' ),
					'openweathermap' => esc_html__( 'OpenWeatherMap (free)', 'jet-elements' ),
				),
			)
		);

		if ( ! $api_key ) {

			$this->add_control(
				'set_api_key',
				array(
					'type' => Controls_Manager::RAW_HTML,
					'raw'  => sprintf(
						esc_html__( 'Please set Weather API key before using this widget. You can create own API key  %1$s. Paste created key on %2$s', 'jet-elements' ),
						'<a target="_blank" href="https://www.weatherbit.io/">' . esc_html__( 'here', 'jet-elements' ) . '</a>',
						'<a target="_blank" href="' . jet_elements_settings()->get_settings_page_link( 'integrations' ) . '">' . esc_html__( 'settings page', 'jet-elements' ) . '</a>'
					),
					'condition' => array(
						'weather_api_provider' => 'weatherbit',
					),
				)
			);
		}
		if ( ! $openweathermap_api_key ) {
			$this->add_control(
				'set_api_key_owm',
				array(
					'type' => Controls_Manager::RAW_HTML,
					'raw'  => sprintf(
						esc_html__( 'Please set OpenWeatherMap API key before using this widget. You can create your API key %1$s. Paste created key on %2$s', 'jet-elements' ),
						'<a target="_blank" href="https://openweathermap.org/appid">' . esc_html__( 'here', 'jet-elements' ) . '</a>',
						'<a target="_blank" href="' . jet_elements_settings()->get_settings_page_link( 'integrations' ) . '">' . esc_html__( 'settings page', 'jet-elements' ) . '</a>'
					),
					'condition' => array(
						'weather_api_provider' => 'openweathermap',
					),
				)
			);
		}

		$this->add_control(
			'location',
			array(
				'label'       => esc_html__( 'Location', 'jet-elements' ),
				'description' => esc_html__( 'Format: City, State(optional), Country code(optional). Example: London, UK.', 'jet-elements' ),
				'type'        => Controls_Manager::TEXT,
				'dynamic'     => array( 'active' => true, ),
				'placeholder' => esc_html__( 'London, UK', 'jet-elements' ),
				'default'     => esc_html__( 'London, UK', 'jet-elements' ),
			)
		);

		$this->add_control(
			'units',
			array(
				'label'   => esc_html__( 'Units', 'jet-elements' ),
				'type'    => Controls_Manager::SELECT,
				'default' => 'metric',
				'options' => array(
					'metric'   => esc_html__( 'Metric', 'jet-elements' ),
					'imperial' => esc_html__( 'Imperial', 'jet-elements' ),
				),
			)
		);

		$this->add_control(
			'time_format',
			array(
				'label'   => esc_html__( 'Time Format', 'jet-elements' ),
				'type'    => Controls_Manager::SELECT,
				'default' => '12',
				'options' => array(
					'12' => esc_html__( '12 hour format', 'jet-elements' ),
					'24' => esc_html__( '24 hour format', 'jet-elements' ),
				),
			)
		);

		$this->add_control(
		   'weather_pricing_plan_notice',
		   array(
		      'type'  => Controls_Manager::RAW_HTML,
	      		'raw'  => sprintf(
					esc_html__( 'If you plan to use the weather widget commercially, please choose the applicable pricing plan: %1$s', 'jet-elements' ),
					'<a target="_blank" href="https://www.weatherbit.io/terms">' . esc_html__( 'Terms and Conditions of Weatherbit', 'jet-elements' ) . '</a>'
				),
		        'content_classes' => 'elementor-panel-alert elementor-panel-alert-info',
				'condition' => array(
					'weather_api_provider' => 'weatherbit',
				),
		   )
		);

		$this->end_controls_section();

		$this->start_controls_section(
			'section_settings',
			array(
				'label' => esc_html__( 'Settings', 'jet-elements' ),
			)
		);

		$this->add_control(
			'show_title',
			array(
				'label'        => esc_html__( 'Show title', 'jet-elements' ),
				'type'         => Controls_Manager::SWITCHER,
				'return_value' => 'true',
				'default'      => 'true',
			)
		);

		$this->add_control(
			'title_type',
			array(
				'label'   => esc_html__( 'Title Text', 'jet-elements' ),
				'type'    => Controls_Manager::SELECT,
				'options' => array(
					'api'      => esc_html__( 'Returned from API', 'jet-elements' ),
					'location' => esc_html__( 'From Location', 'jet-elements' ),
					'custom'   => esc_html__( 'Custom', 'jet-elements' ),
				),
				'default'   => 'api',
				'condition' => array(
					'show_title' => 'true',
				),
			)
		);

		$this->add_control(
			'custom_title',
			array(
				'label'     => esc_html__( 'Custom title', 'jet-elements' ),
				'type'      => Controls_Manager::TEXT,
				'default'   => '',
				'condition' => array(
					'show_title' => 'true',
					'title_type' => 'custom',
				),
			)
		);

		$this->add_control(
			'title_size',
			array(
				'label'   => esc_html__( 'Title HTML Tag', 'jet-elements' ),
				'type'    => Controls_Manager::SELECT,
				'options' => jet_elements_tools()->get_available_title_html_tags(),
				'default'   => 'h3',
				'condition' => array(
					'show_title' => 'true',
				),
			)
		);

		$this->add_control(
			'show_country_name',
			array(
				'label'        => esc_html__( 'Show country name', 'jet-elements' ),
				'type'         => Controls_Manager::SWITCHER,
				'return_value' => 'true',
				'default'      => '',
				'condition'    => array(
					'show_title' => 'true',
					'title_type' => 'api',
				),
			)
		);

		$this->add_control(
			'show_current_weather',
			array(
				'label'        => esc_html__( 'Show current weather', 'jet-elements' ),
				'type'         => Controls_Manager::SWITCHER,
				'return_value' => 'true',
				'default'      => 'true',
				'separator'    => 'before',
			)
		);

		$this->add_control(
			'show_current_weather_details',
			array(
				'label'        => esc_html__( 'Show current weather details (UTC+0)', 'jet-elements' ),
				'type'         => Controls_Manager::SWITCHER,
				'return_value' => 'true',
				'condition'    => array(
					'show_current_weather' => 'true',
				),
			)
		);

		$this->add_control(
			'show_current_weather_utc',
			array(
				'label'        => esc_html__( 'Show current weather details in your timezone.', 'jet-elements' ),
				'type'         => Controls_Manager::SWITCHER,
				'return_value' => 'true',
				'default'      => 'true',
				'condition'    => array(
					'show_current_weather_details' => 'true',
				),
			)
		);

		$this->add_control(
			'show_forecast_weather',
			array(
				'label'        => esc_html__( 'Show forecast weather', 'jet-elements' ),
				'type'         => Controls_Manager::SWITCHER,
				'return_value' => 'true',
				'separator'    => 'before',
			)
		);

		$this->add_control(
			'forecast_count',
			array(
				'label' => esc_html__( 'Number of forecast days', 'jet-elements' ),
				'type'  => Controls_Manager::SLIDER,
				'range' => array(
					'px' => array(
						'min' => 1,
						'max' => 7,
					),
				),
				'default' => array(
					'size' => 5,
				),
				'condition' => array(
					'show_forecast_weather' => 'true',
				),
			)
		);

		$this->add_control(
			'set_api_key',
			array(
				'type' => Controls_Manager::RAW_HTML,
				'raw'  => esc_html__( 
					'OpenWeatherMap has a limitation — the daily forecast is available only for a limited number of days depending on your plan.',
					'jet-elements'
				),
				'content_classes' => 'elementor-panel-alert elementor-panel-alert-info',
				'condition' => array(
					'weather_api_provider' => 'openweathermap',
				),
			)
		);

		$this->end_controls_section();

		$this->start_controls_section(
			'section_background_media',
			array(
				'label' => esc_html__( 'Background Media', 'jet-elements' ),
			)
		);

		$this->add_control(
			'weatherbit_background_media_preview_code',
			array(
				'label'       => esc_html__( 'Preview Weather Code', 'jet-elements' ),
				'description' => esc_html__( 'Works in the editor only. Select a weather code to preview the matching background preset.', 'jet-elements' ),
				'type'        => Controls_Manager::SELECT2,
				'options'     => $this->get_weatherbit_condition_options(),
				'label_block' => true,
				'condition'   => array(
					'weather_api_provider' => 'weatherbit',
				),
			)
		);

		$this->add_control(
			'openweathermap_background_media_preview_code',
			array(
				'label'       => esc_html__( 'Preview Weather Code', 'jet-elements' ),
				'description' => esc_html__( 'Works in the editor only. Select a weather code to preview the matching background preset.', 'jet-elements' ),
				'type'        => Controls_Manager::SELECT2,
				'options'     => $this->get_openweathermap_condition_options(),
				'label_block' => true,
				'condition'   => array(
					'weather_api_provider' => 'openweathermap',
				),
			)
		);

		$this->add_control(
			'weatherbit_background_media_items',
			array(
				'label'         => esc_html__( 'Background Presets', 'jet-elements' ),
				'type'          => Controls_Manager::REPEATER,
				'fields'        => $this->get_background_media_repeater_controls( 'weatherbit' ),
				'title_field'   => '{{{ item_label }}}',
				'prevent_empty' => false,
				'condition'     => array(
					'weather_api_provider' => 'weatherbit',
				),
			)
		);

		$this->add_control(
			'openweathermap_background_media_items',
			array(
				'label'         => esc_html__( 'Background Presets', 'jet-elements' ),
				'type'          => Controls_Manager::REPEATER,
				'fields'        => $this->get_background_media_repeater_controls( 'openweathermap' ),
				'title_field'   => '{{{ item_label }}}',
				'prevent_empty' => false,
				'condition'     => array(
					'weather_api_provider' => 'openweathermap',
				),
			)
		);

		$this->end_controls_section();

		$this->_start_controls_section(
			'section_title_style',
			array(
				'label'     => esc_html__( 'Title', 'jet-elements' ),
				'tab'       => Controls_Manager::TAB_STYLE,
				'condition' => array(
					'show_title' => 'true',
				),
			)
		);

		$this->_add_control(
			'title_color',
			array(
				'label' => esc_html__( 'Color', 'jet-elements' ),
				'type'  => Controls_Manager::COLOR,
				'selectors' => array(
					'{{WRAPPER}} ' . $css_scheme['title'] => 'color: {{VALUE}};',
				),
			),
			25
		);

		$this->_add_group_control(
			Group_Control_Typography::get_type(),
			array(
				'name'     => 'title_typography',
				'selector' => '{{WRAPPER}} ' . $css_scheme['title'],
			),
			50
		);

		$this->_add_responsive_control(
			'title_align',
			array(
				'label' => esc_html__( 'Alignment', 'jet-elements' ),
				'type'  => Controls_Manager::CHOOSE,
				'options' => array(
					'left' => array(
						'title' => esc_html__( 'Left', 'jet-elements' ),
						'icon'  => 'fa fa-align-left',
					),
					'center' => array(
						'title' => esc_html__( 'Center', 'jet-elements' ),
						'icon'  => 'fa fa-align-center',
					),
					'right' => array(
						'title' => esc_html__( 'Right', 'jet-elements' ),
						'icon'  => 'fa fa-align-right',
					),
					'justify' => array(
						'title' => esc_html__( 'Justified', 'jet-elements' ),
						'icon'  => 'fa fa-align-justify',
					),
				),
				'selectors' => array(
					'{{WRAPPER}} ' . $css_scheme['title'] => 'text-align: {{VALUE}};',
				),
				'classes' => 'jet-elements-text-align-control',
			),
			50
		);

		$this->_add_responsive_control(
			'title_margin',
			array(
				'label'      => esc_html__( 'Margin', 'jet-elements' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', '%', 'custom' ),
				'selectors'  => array(
					'{{WRAPPER}} ' . $css_scheme['title'] => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				),
			),
			25
		);

		$this->_add_responsive_control(
			'title_padding',
			array(
				'label'      => esc_html__( 'Padding', 'jet-elements' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', '%', 'custom' ),
				'selectors'  => array(
					'{{WRAPPER}} ' . $css_scheme['title'] => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				),
			),
			75
		);

		$this->_add_group_control(
			Group_Control_Border::get_type(),
			array(
				'name'     => 'title_border',
				'selector' => '{{WRAPPER}} ' . $css_scheme['title'],
			),
			100
		);

		$this->_add_group_control(
			Group_Control_Text_Shadow::get_type(),
			array(
				'name'     => 'title_text_shadow',
				'selector' => '{{WRAPPER}} ' . $css_scheme['title'],
			),
			100
		);

		$this->_end_controls_section();

		$this->_start_controls_section(
			'section_current_style',
			array(
				'label'     => esc_html__( 'Current Weather', 'jet-elements' ),
				'tab'       => Controls_Manager::TAB_STYLE,
				'condition' => array(
					'show_current_weather' => 'true',
				),
			)
		);

		$this->_add_control(
			'current_container_heading',
			array(
				'label' => esc_html__( 'Container', 'jet-elements' ),
				'type'  => Controls_Manager::HEADING,
			),
			25
		);

		$this->_add_responsive_control(
			'current_container_margin',
			array(
				'label'      => esc_html__( 'Margin', 'jet-elements' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', '%', 'custom' ),
				'selectors'  => array(
					'{{WRAPPER}} ' . $css_scheme['current_container'] => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				),
			),
			25
		);

		$this->_add_responsive_control(
			'current_container_padding',
			array(
				'label'      => esc_html__( 'Padding', 'jet-elements' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', '%', 'custom' ),
				'selectors'  => array(
					'{{WRAPPER}} ' . $css_scheme['current_container'] => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				),
			),
			25
		);

		$this->_add_group_control(
			Group_Control_Border::get_type(),
			array(
				'name'     => 'current_container_border',
				'selector' => '{{WRAPPER}} ' . $css_scheme['current_container'],
			),
			75
		);

		$this->_add_control(
			'current_temp_heading',
			array(
				'label'     => esc_html__( 'Temperature', 'jet-elements' ),
				'type'      => Controls_Manager::HEADING,
				'separator' => 'before',
			),
			25
		);

		$this->_add_control(
			'current_temp_color',
			array(
				'label' => esc_html__( 'Color', 'jet-elements' ),
				'type'  => Controls_Manager::COLOR,
				'selectors' => array(
					'{{WRAPPER}} ' . $css_scheme['current_temp'] => 'color: {{VALUE}};',
				),
			),
			25
		);

		$this->_add_group_control(
			Group_Control_Typography::get_type(),
			array(
				'name'     => 'current_temp_typography',
				'selector' => '{{WRAPPER}} ' . $css_scheme['current_temp'],
			),
			50
		);

		$this->_add_control(
			'current_icon_heading',
			array(
				'label'     => esc_html__( 'Icon', 'jet-elements' ),
				'type'      => Controls_Manager::HEADING,
				'separator' => 'before',
			),
			25
		);

		$this->_add_control(
			'current_icon_color',
			array(
				'label' => esc_html__( 'Color', 'jet-elements' ),
				'type'  => Controls_Manager::COLOR,
				'selectors' => array(
					'{{WRAPPER}} ' . $css_scheme['current_icon'] => 'color: {{VALUE}};',
				),
			),
			25
		);

		$this->_add_control(
			'current_icon_size',
			array(
				'label'      => esc_html__( 'Font Size', 'jet-elements' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px', 'em', 'rem', 'custom' ),
				'range'      => array(
					'px' => array(
						'min' => 1,
						'max' => 200,
					),
				),
				'selectors' => array(
					'{{WRAPPER}} ' . $css_scheme['current_icon'] => 'font-size: {{SIZE}}{{UNIT}};',
				),
			),
			50
		);

		$this->_add_control(
			'current_desc_heading',
			array(
				'label'     => esc_html__( 'Description', 'jet-elements' ),
				'type'      => Controls_Manager::HEADING,
				'separator' => 'before',
			),
			25
		);

		$this->_add_control(
			'current_desc_color',
			array(
				'label' => esc_html__( 'Color', 'jet-elements' ),
				'type'  => Controls_Manager::COLOR,
				'selectors' => array(
					'{{WRAPPER}} ' . $css_scheme['current_desc'] => 'color: {{VALUE}};',
				),
			),
			25
		);

		$this->_add_group_control(
			Group_Control_Typography::get_type(),
			array(
				'name'     => 'current_desc_typography',
				'selector' => '{{WRAPPER}} ' . $css_scheme['current_desc'],
			),
			50
		);

		$this->_add_control(
			'current_desc_gap',
			array(
				'label' => esc_html__( 'Gap', 'jet-elements' ),
				'type'  => Controls_Manager::SLIDER,
				'range' => array(
					'px' => array(
						'min' => 0,
						'max' => 30,
					),
				),
				'selectors' => array(
					'{{WRAPPER}} ' . $css_scheme['current_desc'] => 'margin-top: {{SIZE}}{{UNIT}};',
				),
			),
			25
		);

		$this->_end_controls_section();

		$this->_start_controls_section(
			'section_current_details_style',
			array(
				'label'     => esc_html__( 'Details Weather', 'jet-elements' ),
				'tab'       => Controls_Manager::TAB_STYLE,
				'condition' => array(
					'show_current_weather'         => 'true',
					'show_current_weather_details' => 'true',
				),
			)
		);

		$this->_add_control(
			'current_details_container_heading',
			array(
				'label' => esc_html__( 'Container', 'jet-elements' ),
				'type'  => Controls_Manager::HEADING,
			),
			25
		);

		$this->_add_control(
			'current_details_margin',
			array(
				'label'      => esc_html__( 'Margin', 'jet-elements' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', '%', 'custom' ),
				'selectors'  => array(
					'{{WRAPPER}} ' . $css_scheme['current_details'] => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				),
			),
			25
		);

		$this->_add_control(
			'current_details_padding',
			array(
				'label'      => esc_html__( 'Padding', 'jet-elements' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', '%', 'custom' ),
				'selectors'  => array(
					'{{WRAPPER}} ' . $css_scheme['current_details'] => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				),
			),
			25
		);

		$this->_add_group_control(
			Group_Control_Border::get_type(),
			array(
				'name'     => 'current_details_border',
				'selector' => '{{WRAPPER}} ' . $css_scheme['current_details'],
			),
			75
		);

		$this->_add_control(
			'current_details_items_heading',
			array(
				'label'     => esc_html__( 'Items', 'jet-elements' ),
				'type'      => Controls_Manager::HEADING,
				'separator' => 'before',
			),
			25
		);

		$this->_add_control(
			'current_details_color',
			array(
				'label' => esc_html__( 'Color', 'jet-elements' ),
				'type'  => Controls_Manager::COLOR,
				'selectors' => array(
					'{{WRAPPER}} ' . $css_scheme['current_details'] => 'color: {{VALUE}};',
				),
			),
			25
		);

		$this->_add_group_control(
			Group_Control_Typography::get_type(),
			array(
				'name'     => 'current_details_typography',
				'selector' => '{{WRAPPER}} ' . $css_scheme['current_details'],
			),
			50
		);

		$this->_add_group_control(
			Group_Control_Typography::get_type(),
			array(
				'name'     => 'current_day_typography',
				'label'    => esc_html__( 'Day typography', 'jet-elements' ),
				'selector' => '{{WRAPPER}} ' . $css_scheme['current_day'],
			),
			50
		);

		$this->_add_control(
			'current_details_item_gap',
			array(
				'label' => esc_html__( 'Gap', 'jet-elements' ),
				'type'  => Controls_Manager::SLIDER,
				'range' => array(
					'px' => array(
						'min' => 0,
						'max' => 30,
					),
				),
				'selectors' => array(
					'{{WRAPPER}} ' . $css_scheme['current_details'] => 'row-gap: {{SIZE}}{{UNIT}};',
				),
			),
			25
		);

		$this->_add_control(
			'current_details_icon_heading',
			array(
				'label'     => esc_html__( 'Icon', 'jet-elements' ),
				'type'      => Controls_Manager::HEADING,
				'separator' => 'before',
			),
			25
		);

		$this->_add_control(
			'current_details_icon_color',
			array(
				'label' => esc_html__( 'Color', 'jet-elements' ),
				'type'  => Controls_Manager::COLOR,
				'selectors' => array(
					'{{WRAPPER}} ' . $css_scheme['current_details_icon'] => 'color: {{VALUE}};',
				),
			),
			25
		);

		$this->_add_control(
			'current_details_icon_size',
			array(
				'label'      => esc_html__( 'Font Size', 'jet-elements' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px', 'em', 'rem', 'custom' ),
				'range'      => array(
					'px' => array(
						'min' => 1,
						'max' => 200,
					),
				),
				'selectors'  => array(
					'{{WRAPPER}} ' . $css_scheme['current_details_icon'] => 'font-size: {{SIZE}}{{UNIT}};',
				),
			),
			50
		);

		$this->_end_controls_section();

		$this->_start_controls_section(
			'section_forecast_style',
			array(
				'label'     => esc_html__( 'Forecast Weather', 'jet-elements' ),
				'tab'       => Controls_Manager::TAB_STYLE,
				'condition' => array(
					'show_forecast_weather' => 'true',
				),
			)
		);

		$this->_add_control(
			'forecast_container_heading',
			array(
				'label' => esc_html__( 'Container', 'jet-elements' ),
				'type'  => Controls_Manager::HEADING,
			),
			25
		);

		$this->_add_responsive_control(
			'forecast_container_margin',
			array(
				'label'      => esc_html__( 'Margin', 'jet-elements' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', '%', 'custom' ),
				'selectors'  => array(
					'{{WRAPPER}} ' . $css_scheme['forecast_container'] => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				),
			),
			25
		);

		$this->_add_responsive_control(
			'forecast_container_padding',
			array(
				'label'      => esc_html__( 'Padding', 'jet-elements' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', '%', 'custom' ),
				'selectors'  => array(
					'{{WRAPPER}} ' . $css_scheme['forecast_container'] => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				),
			),
			25
		);

		$this->_add_group_control(
			Group_Control_Border::get_type(),
			array(
				'name'     => 'forecast_container_border',
				'selector' => '{{WRAPPER}} ' . $css_scheme['forecast_container'],
			),
			75
		);

		$this->_add_control(
			'forecast_item_heading',
			array(
				'label'     => esc_html__( 'Items', 'jet-elements' ),
				'type'      => Controls_Manager::HEADING,
				'separator' => 'before',
			),
			25
		);

		$this->_add_control(
			'forecast_item_color',
			array(
				'label' => esc_html__( 'Color', 'jet-elements' ),
				'type'  => Controls_Manager::COLOR,
				'selectors' => array(
					'{{WRAPPER}} ' . $css_scheme['forecast_item'] => 'color: {{VALUE}};',
				),
			),
			25
		);

		$this->_add_group_control(
			Group_Control_Typography::get_type(),
			array(
				'name'     => 'forecast_item_typography',
				'selector' => '{{WRAPPER}} ' . $css_scheme['forecast_item'],
			),
			50
		);

		$this->_add_group_control(
			Group_Control_Typography::get_type(),
			array(
				'name'     => 'forecast_day_typography',
				'label'    => esc_html__( 'Day typography', 'jet-elements' ),
				'selector' => '{{WRAPPER}} ' . $css_scheme['forecast_day'],
			),
			50
		);

		$this->_add_responsive_control(
			'forecast_item_margin',
			array(
				'label'      => esc_html__( 'Margin', 'jet-elements' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', '%', 'custom' ),
				'selectors'  => array(
					'{{WRAPPER}} ' . $css_scheme['forecast_item'] => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				),
			),
			25
		);

		$this->_add_responsive_control(
			'forecast_item_padding',
			array(
				'label'      => esc_html__( 'Padding', 'jet-elements' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', '%', 'custom' ),
				'selectors'  => array(
					'{{WRAPPER}} ' . $css_scheme['forecast_item'] => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				),
			),
			25
		);

		$this->_add_control(
			'forecast_item_divider',
			array(
				'label'        => esc_html__( 'Divider', 'jet-elements' ),
				'type'         => Controls_Manager::SWITCHER,
				'return_value' => 'yes',
			),
			50
		);

		$this->_add_control(
			'forecast_item_divider_style',
			array(
				'label' => esc_html__( 'Style', 'jet-elements' ),
				'type'  => Controls_Manager::SELECT,
				'options' => array(
					'solid'  => esc_html__( 'Solid', 'jet-elements' ),
					'double' => esc_html__( 'Double', 'jet-elements' ),
					'dotted' => esc_html__( 'Dotted', 'jet-elements' ),
					'dashed' => esc_html__( 'Dashed', 'jet-elements' ),
				),
				'default' => 'solid',
				'condition' => array(
					'forecast_item_divider' => 'yes',
				),
				'selectors' => array(
					'{{WRAPPER}} ' . $css_scheme['forecast_item'] . ':not(:first-child)' => 'border-top-style: {{VALUE}}',
				),
			),
			50
		);

		$this->_add_control(
			'forecast_item_divider_weight',
			array(
				'label'   => esc_html__( 'Weight', 'jet-elements' ),
				'type'    => Controls_Manager::SLIDER,
				'default' => array(
					'size' => 1,
				),
				'range' => array(
					'px' => array(
						'min' => 1,
						'max' => 20,
					),
				),
				'condition' => array(
					'forecast_item_divider' => 'yes',
				),
				'selectors' => array(
					'{{WRAPPER}} ' . $css_scheme['forecast_item'] . ':not(:first-child)' => 'border-top-width: {{SIZE}}{{UNIT}}',
				),
			),
			50
		);

		$this->_add_control(
			'forecast_item_divider_color',
			array(
				'label'     => esc_html__( 'Color', 'jet-elements' ),
				'type'      => Controls_Manager::COLOR,
				'condition' => array(
					'forecast_item_divider' => 'yes',
				),
				'selectors' => array(
					'{{WRAPPER}} ' . $css_scheme['forecast_item'] . ':not(:first-child)' => 'border-color: {{VALUE}}',
				),
			),
			50
		);

		$this->_add_control(
			'forecast_icon_heading',
			array(
				'label'     => esc_html__( 'Icon', 'jet-elements' ),
				'type'      => Controls_Manager::HEADING,
				'separator' => 'before',
			),
			25
		);

		$this->_add_control(
			'forecast_icon_color',
			array(
				'label' => esc_html__( 'Color', 'jet-elements' ),
				'type'  => Controls_Manager::COLOR,
				'selectors' => array(
					'{{WRAPPER}} ' . $css_scheme['forecast_icon'] => 'color: {{VALUE}};',
				),
			),
			25
		);

		$this->_add_control(
			'forecast_icon_size',
			array(
				'label'      => esc_html__( 'Font Size', 'jet-elements' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px', 'em', 'rem', 'custom' ),
				'range'      => array(
					'px' => array(
						'min' => 1,
						'max' => 200,
					),
				),
				'selectors'  => array(
					'{{WRAPPER}} ' . $css_scheme['forecast_icon'] => 'font-size: {{SIZE}}{{UNIT}};',
				),
			),
			50
		);

		$this->_end_controls_section();

		$this->_start_controls_section(
			'section_background_media_style',
			array(
				'label' => esc_html__( 'Background Media', 'jet-elements' ),
				'tab'   => Controls_Manager::TAB_STYLE,
			)
		);

		$this->_add_responsive_control(
			'background_media_min_height',
			array(
				'label'      => esc_html__( 'Min Height', 'jet-elements' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px', 'vh', 'custom' ),
				'range'      => array(
					'px' => array(
						'min' => 0,
						'max' => 1000,
					),
					'vh' => array(
						'min' => 0,
						'max' => 100,
					),
				),
				'selectors'  => array(
					'{{WRAPPER}} .jet-weather' => 'min-height: {{SIZE}}{{UNIT}};',
				),
			),
			25
		);

		$this->_add_responsive_control(
			'background_media_content_padding',
			array(
				'label'      => esc_html__( 'Padding', 'jet-elements' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', '%', 'custom' ),
				'selectors'  => array(
					'{{WRAPPER}} .jet-weather__container' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				),
			),
			50
		);

		$this->_add_group_control(
			Group_Control_Border::get_type(),
			array(
				'name'     => 'background_media_border',
				'selector' => '{{WRAPPER}} .jet-weather',
			),
			75
		);

		$this->_add_responsive_control(
			'background_media_border_radius',
			array(
				'label'      => esc_html__( 'Border Radius', 'jet-elements' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', '%', 'custom' ),
				'selectors'  => array(
					'{{WRAPPER}} .jet-weather' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
					'{{WRAPPER}} .jet-weather__media' => 'border-radius: inherit;',
				),
			),
			100
		);

		$this->_end_controls_section();
	}

	protected function render() {
		$this->_context = 'render';

		$this->_open_wrap();

		$this->weather_data = $this->get_weather_data();

		if ( ! empty( $this->weather_data ) ) {
			include $this->_get_global_template( 'index' );
		}

		$this->_close_wrap();
	}

	/**
	 * Get weather data.
	 *
	 * @return array|bool|mixed
	 */
	public function get_weather_data() {

		$settings      = $this->get_settings_for_display();
		$location_type = isset( $settings['location_type'] ) ? $settings['location_type'] : 'city';
		$provider      = isset( $settings['weather_api_provider'] ) ? $settings['weather_api_provider'] : 'weatherbit';
	
		// API KEYS
		$weatherbit_api_key = jet_elements_settings()->get( 'weather_api_key' );
		$owm_api_key        = jet_elements_settings()->get( 'openweathermap_api_key' );
	
		$api_key = ( 'openweathermap' === $provider ) ? $owm_api_key : $weatherbit_api_key;
	
		// Do nothing if api key not provided
		if ( ! $api_key ) {
			$message = esc_html__( 'Please set Weather API key before using this widget.', 'jet-elements' );
			echo $this->get_weather_notice( $message );
			return false;
		}
	
		$location_identifier = $this->get_location_identifier( $settings, $location_type );
	
		if ( empty( $location_identifier ) ) {
			return false;
		}
	
		$units = $this->get_units_param( $settings['units'] );
	
		$transient_key = sprintf(
			'jet-weather-data-%1$s-%2$s',
			$provider,
			md5( $location_identifier . $units )
		);
	
		$data = get_transient( $transient_key );
	
		if ( $data ) {
			return $data;
		}

		$api_key = esc_attr( $api_key );
		$units   = esc_attr( $units );
	
		if ( 'weatherbit' === $provider ) {
	
			$request_args = array(
				'key'   => urlencode( $api_key ),
				'units' => urlencode( $units ),
			);
	
			$request_args = $this->add_location_params( $request_args, $settings, $location_type );

			$current_request_url = add_query_arg( $request_args, $this->current_weather_api_url );
			$current_request_data = $this->_get_request_data( $current_request_url );
	
			if ( ! $current_request_data ) {
				echo $this->get_weather_notice( esc_html__( 'Weather data of this location not found.', 'jet-elements' ) );
				return false;
			}
	
			if ( isset( $current_request_data['error'] ) ) {
				echo $this->get_weather_notice( $current_request_data['error'] );
				return false;
			}

			$request_args['days'] = 8;
			$forecast_request_url = add_query_arg( $request_args, $this->forecast_weather_api_url );
			$forecast_request_data = $this->_get_request_data( $forecast_request_url );
	
			if ( isset( $forecast_request_data['error'] ) ) {
				echo $this->get_weather_notice( $forecast_request_data['error'] );
				return false;
			}
	
			$data = $this->prepare_weather_data( $current_request_data, $forecast_request_data );
		}
	
		else {
	
			$request_args = array(
				'appid' => urlencode( $api_key ),
				'units' => ( 'M' === $units ? 'metric' : 'imperial' ),
			);

			$request_args = $this->add_location_params( $request_args, $settings, $location_type );
	
			if ( isset( $request_args['city'] ) ) {
				$request_args['q'] = $request_args['city'];
				unset( $request_args['city'] );
			}

			$current_request_url = add_query_arg( $request_args, $this->owm_current_url );
			$current_request_data = $this->_get_request_data( $current_request_url );
	
			if ( ! $current_request_data || ( isset( $current_request_data['cod'] ) && (int) $current_request_data['cod'] !== 200 ) ) {
	
				$message = isset( $current_request_data['message'] )
					? $current_request_data['message']
					: esc_html__( 'Weather data of this location not found.', 'jet-elements' );
	
				echo $this->get_weather_notice( $message );
				return false;
			}

			$forecast_request_url = add_query_arg( $request_args, $this->owm_forecast_url );
			$forecast_request_data = $this->_get_request_data( $forecast_request_url );
	
			if ( isset( $forecast_request_data['cod'] ) && (int) $forecast_request_data['cod'] !== 200 ) {
				echo $this->get_weather_notice( $forecast_request_data['message'] );
				return false;
			}
	
			$data = $this->normalize_owm_data( $current_request_data, $forecast_request_data );
		}
	
		if ( empty( $data ) ) {
			return false;
		}
	
		set_transient(
			$transient_key,
			$data,
			apply_filters( 'jet-elements/weather/cached-time', HOUR_IN_SECONDS )
		);
	
		return $data;
	}

	/**
	 * Get units param for request args.
	 *
	 * @param string $unit
	 *
	 * @return string
	 */
	public function get_units_param( $unit ) {

		if ( 'imperial' === $unit ) {
			return 'I';
		}

		return 'M';
	}

	/**
	 * Get location identifier for caching and validation.
	 *
	 * @param array  $settings      Widget settings.
	 * @param string $location_type Location type.
	 *
	 * @return string
	 */
	public function get_location_identifier( $settings, $location_type ) {
		$identifier = '';

		switch ( $location_type ) {
			case 'coordinates':
				$coordinates = isset( $settings['coordinates'] ) ? trim( $settings['coordinates'] ) : '';
				
				if ( ! empty( $coordinates ) ) {
					$parsed = $this->parse_coordinates( $coordinates );
					
					if ( $parsed && ! empty( $parsed['lat'] ) && ! empty( $parsed['lon'] ) ) {
						$identifier = sprintf( 'lat:%s|lon:%s', $parsed['lat'], $parsed['lon'] );
					}
				}
				break;

			case 'city':
			default:
				$identifier = isset( $settings['location'] ) ? trim( $settings['location'] ) : '';
				break;
		}

		return $identifier;
	}

	/**
	 * Add location parameters to request args based on location type.
	 *
	 * @param array  $request_args  Request arguments.
	 * @param array  $settings      Widget settings.
	 * @param string $location_type Location type.
	 *
	 * @return array
	 */
	public function add_location_params( $request_args, $settings, $location_type ) {

		switch ( $location_type ) {
			case 'coordinates':
				$coordinates = isset( $settings['coordinates'] ) ? trim( $settings['coordinates'] ) : '';
				
				if ( ! empty( $coordinates ) ) {
					$parsed = $this->parse_coordinates( $coordinates );
					
					if ( $parsed && ! empty( $parsed['lat'] ) && ! empty( $parsed['lon'] ) ) {
						$request_args['lat'] = urlencode( esc_attr( $parsed['lat'] ) );
						$request_args['lon'] = urlencode( esc_attr( $parsed['lon'] ) );
					}
				}
				break;

			case 'city':
			default:
				$location = isset( $settings['location'] ) ? trim( $settings['location'] ) : '';
				
				if ( ! empty( $location ) ) {
					$request_args['city'] = urlencode( esc_attr( $location ) );
				}
				break;
		}

		return $request_args;
	}

	/**
	 * Parse coordinates from string.
	 * Supports formats: "lat;lon", "lat,lon"
	 *
	 * @param string $coordinates Coordinates string.
	 *
	 * @return array|bool Array with 'lat' and 'lon' keys or false on failure.
	 */
	public function parse_coordinates( $coordinates ) {
		
		if ( empty( $coordinates ) ) {
			return false;
		}

		// Split by ; or ,
		$parts = preg_split( '/[;,]/', $coordinates );
		if ( count( $parts ) === 2 ) {
			$lat = floatval( str_replace( ',', '.', trim( $parts[0] ) ) );
			$lon = floatval( str_replace( ',', '.', trim( $parts[1] ) ) );
		} else {
			$lat = null;
			$lon = null;
		}

		// Validate ranges
		if ( $lat === null || $lon === null || $lat < -90 || $lat > 90 || $lon < -180 || $lon > 180 ) {
			$message = esc_html__( 'Invalid coordinates format or values outside valid range', 'jet-elements' );
			echo $this->get_weather_notice( $message ); // phpcs:ignore
			return false;
		}

		return array(
			'lat' => $lat,
			'lon' => $lon,
		);
	}

	/**
	 * Get request data.
	 *
	 * @param string $url Request url.
	 *
	 * @return array|bool
	 */
	public function _get_request_data( $url ) {

		$response = wp_remote_get( $url, array( 'timeout' => 30 ) );

		if ( ! $response || is_wp_error( $response ) ) {
			return false;
		}

		$data = wp_remote_retrieve_body( $response );

		if ( ! $data || is_wp_error( $data ) ) {
			return false;
		}

		$data = json_decode( $data, true );

		if ( empty( $data ) ) {
			return false;
		}

		return $data;
	}

	/**
	 * Prepare weather data.
	 *
	 * @param array $current_data  Current weather data.
	 * @param array $forecast_data Forecast weather data.
	 *
	 * @return array
	 */
	public function prepare_weather_data( $current_data = array(), $forecast_data = array() ) {

		$data = array(
			// Location data
			'location' => array(
				'city'    => $current_data['data'][0]['city_name'],
				'country' => $current_data['data'][0]['country_code'],
			),

			// Current data
			'current' => array(
				'code'       => $current_data['data'][0]['weather']['code'],
				'is_day'     => 'd' === $current_data['data'][0]['pod'],
				'temp'       => $current_data['data'][0]['temp'],
				'temp_min'   => $forecast_data['data'][0]['min_temp'],
				'temp_max'   => $forecast_data['data'][0]['max_temp'],
				'wind_speed' => $current_data['data'][0]['wind_spd'],
				'wind_deg'   => $current_data['data'][0]['wind_dir'],
				'wind_dir'   => $current_data['data'][0]['wind_cdir'],
				'humidity'   => $current_data['data'][0]['rh'] . '%',
				'pressure'   => $current_data['data'][0]['pres'],
				'sunrise'    => $current_data['data'][0]['sunrise'],
				'sunset'     => $current_data['data'][0]['sunset'],
			),

			// Forecast data
			'forecast' => array(),
		);

		$forecast_items_count = ! empty( $forecast_data['data'] ) && is_array( $forecast_data['data'] )
			? min( 8, count( $forecast_data['data'] ) )
			: 0;

		for ( $i = 0; $i < $forecast_items_count; $i ++ ) {
			$data['forecast'][] = array(
				'code'     => $forecast_data['data'][ $i ]['weather']['code'],
				'date'     => $forecast_data['data'][ $i ]['valid_date'],
				'temp_min' => $forecast_data['data'][ $i ]['min_temp'],
				'temp_max' => $forecast_data['data'][ $i ]['max_temp'],
			);
		}

		return $data;
	}

	public function get_background_media_repeater_controls( $provider ) {
		$repeater = new Repeater();

		$repeater->add_control(
			'item_label',
			array(
				'label'       => esc_html__( 'Preset Name', 'jet-elements' ),
				'type'        => Controls_Manager::TEXT,
				'default'     => '',
				'placeholder' => esc_html__( 'Rain', 'jet-elements' ),
			)
		);

		$repeater->add_control(
			'weather_codes',
			array(
				'label'       => 'openweathermap' === $provider ? esc_html__( 'OpenWeatherMap condition codes', 'jet-elements' ) : esc_html__( 'Weatherbit condition codes', 'jet-elements' ),
				'type'        => Controls_Manager::SELECT2,
				'multiple'    => true,
				'label_block' => true,
				'options'     => 'openweathermap' === $provider ? $this->get_openweathermap_condition_options() : $this->get_weatherbit_condition_options(),
			)
		);

		$repeater->add_control(
			'weather_codes_help',
			array(
				'type'            => Controls_Manager::RAW_HTML,
				'raw'             => sprintf(
					__( 'See all condition codes: <a href="%s" target="_blank">here</a>', 'jet-elements' ),
					esc_url( 'openweathermap' === $provider ? 'https://openweathermap.org/api/weather-conditions#Weather-Condition-Codes-2' : 'https://www.weatherbit.io/api/codes' )
				),
				'content_classes' => 'elementor-descriptor',
			)
		);

		$repeater->add_control(
			'media_type',
			array(
				'label'   => esc_html__( 'Media type', 'jet-elements' ),
				'type'    => Controls_Manager::SELECT,
				'default' => 'image',
				'options' => array(
					'image' => esc_html__( 'Image', 'jet-elements' ),
					'video' => esc_html__( 'Video', 'jet-elements' ),
				),
			)
		);

		$repeater->add_control(
			'background_image',
			array(
				'label' => esc_html__( 'Background image', 'jet-elements' ),
				'type'  => Controls_Manager::MEDIA,
				'dynamic' => array( 'active' => true ),
				'condition' => array(
					'media_type' => 'image',
				),
			)
		);

		$repeater->add_control(
			'background_video',
			array(
				'label'      => esc_html__( 'Background video', 'jet-elements' ),
				'type'       => Controls_Manager::MEDIA,
				'media_type' => 'video',
				'dynamic' => array( 'active' => true ),
				'condition'  => array(
					'media_type' => 'video',
				),
			)
		);

		return $repeater->get_controls();
	}

	public function get_weatherbit_condition_options() {
		$options    = array();
		$conditions = $this->get_weatherbit_conditions();

		foreach ( $conditions as $code => $desc ) {
			$options[ $code ] = sprintf( '%1$s (%2$s)', $desc, $code );
		}

		return $options;
	}

	public function get_weatherbit_conditions() {
		return array(
			'200' => esc_html_x( 'Thunderstorm with light rain', 'Weather description', 'jet-elements' ),
			'201' => esc_html_x( 'Thunderstorm with rain', 'Weather description', 'jet-elements' ),
			'202' => esc_html_x( 'Thunderstorm with heavy rain', 'Weather description', 'jet-elements' ),
			'230' => esc_html_x( 'Thunderstorm with light drizzle', 'Weather description', 'jet-elements' ),
			'231' => esc_html_x( 'Thunderstorm with drizzle', 'Weather description', 'jet-elements' ),
			'232' => esc_html_x( 'Thunderstorm with heavy drizzle', 'Weather description', 'jet-elements' ),
			'233' => esc_html_x( 'Thunderstorm with Hail', 'Weather description', 'jet-elements' ),
			'300' => esc_html_x( 'Light Drizzle', 'Weather description', 'jet-elements' ),
			'301' => esc_html_x( 'Drizzle', 'Weather description', 'jet-elements' ),
			'302' => esc_html_x( 'Heavy Drizzle', 'Weather description', 'jet-elements' ),
			'500' => esc_html_x( 'Light Rain', 'Weather description', 'jet-elements' ),
			'501' => esc_html_x( 'Moderate Rain', 'Weather description', 'jet-elements' ),
			'502' => esc_html_x( 'Heavy Rain', 'Weather description', 'jet-elements' ),
			'511' => esc_html_x( 'Freezing rain', 'Weather description', 'jet-elements' ),
			'520' => esc_html_x( 'Light shower rain', 'Weather description', 'jet-elements' ),
			'521' => esc_html_x( 'Shower rain', 'Weather description', 'jet-elements' ),
			'522' => esc_html_x( 'Heavy shower rain', 'Weather description', 'jet-elements' ),
			'600' => esc_html_x( 'Light snow', 'Weather description', 'jet-elements' ),
			'601' => esc_html_x( 'Snow', 'Weather description', 'jet-elements' ),
			'602' => esc_html_x( 'Heavy Snow', 'Weather description', 'jet-elements' ),
			'610' => esc_html_x( 'Mix snow/rain', 'Weather description', 'jet-elements' ),
			'611' => esc_html_x( 'Sleet', 'Weather description', 'jet-elements' ),
			'612' => esc_html_x( 'Heavy sleet', 'Weather description', 'jet-elements' ),
			'621' => esc_html_x( 'Snow shower', 'Weather description', 'jet-elements' ),
			'622' => esc_html_x( 'Heavy snow shower', 'Weather description', 'jet-elements' ),
			'623' => esc_html_x( 'Flurries', 'Weather description', 'jet-elements' ),
			'700' => esc_html_x( 'Mist', 'Weather description', 'jet-elements' ),
			'711' => esc_html_x( 'Smoke', 'Weather description', 'jet-elements' ),
			'721' => esc_html_x( 'Haze', 'Weather description', 'jet-elements' ),
			'731' => esc_html_x( 'Sand/dust', 'Weather description', 'jet-elements' ),
			'741' => esc_html_x( 'Fog', 'Weather description', 'jet-elements' ),
			'751' => esc_html_x( 'Freezing Fog', 'Weather description', 'jet-elements' ),
			'800' => esc_html_x( 'Clear sky', 'Weather description', 'jet-elements' ),
			'801' => esc_html_x( 'Few clouds', 'Weather description', 'jet-elements' ),
			'802' => esc_html_x( 'Scattered clouds', 'Weather description', 'jet-elements' ),
			'803' => esc_html_x( 'Broken clouds', 'Weather description', 'jet-elements' ),
			'804' => esc_html_x( 'Overcast clouds', 'Weather description', 'jet-elements' ),
			'900' => esc_html_x( 'Unknown Precipitation', 'Weather description', 'jet-elements' ),
		);
	}

	public function get_openweathermap_condition_options() {
		$conditions = array(
			'200' => esc_html_x( 'Thunderstorm with light rain', 'Weather description', 'jet-elements' ),
			'201' => esc_html_x( 'Thunderstorm with rain', 'Weather description', 'jet-elements' ),
			'202' => esc_html_x( 'Thunderstorm with heavy rain', 'Weather description', 'jet-elements' ),
			'210' => esc_html_x( 'Light thunderstorm', 'Weather description', 'jet-elements' ),
			'211' => esc_html_x( 'Thunderstorm', 'Weather description', 'jet-elements' ),
			'212' => esc_html_x( 'Heavy thunderstorm', 'Weather description', 'jet-elements' ),
			'221' => esc_html_x( 'Ragged thunderstorm', 'Weather description', 'jet-elements' ),
			'230' => esc_html_x( 'Thunderstorm with light drizzle', 'Weather description', 'jet-elements' ),
			'231' => esc_html_x( 'Thunderstorm with drizzle', 'Weather description', 'jet-elements' ),
			'232' => esc_html_x( 'Thunderstorm with heavy drizzle', 'Weather description', 'jet-elements' ),
			'300' => esc_html_x( 'Light intensity drizzle', 'Weather description', 'jet-elements' ),
			'301' => esc_html_x( 'Drizzle', 'Weather description', 'jet-elements' ),
			'302' => esc_html_x( 'Heavy intensity drizzle', 'Weather description', 'jet-elements' ),
			'310' => esc_html_x( 'Light intensity drizzle rain', 'Weather description', 'jet-elements' ),
			'311' => esc_html_x( 'Drizzle rain', 'Weather description', 'jet-elements' ),
			'312' => esc_html_x( 'Heavy intensity drizzle rain', 'Weather description', 'jet-elements' ),
			'313' => esc_html_x( 'Shower rain and drizzle', 'Weather description', 'jet-elements' ),
			'314' => esc_html_x( 'Heavy shower rain and drizzle', 'Weather description', 'jet-elements' ),
			'321' => esc_html_x( 'Shower drizzle', 'Weather description', 'jet-elements' ),
			'500' => esc_html_x( 'Light rain', 'Weather description', 'jet-elements' ),
			'501' => esc_html_x( 'Moderate rain', 'Weather description', 'jet-elements' ),
			'502' => esc_html_x( 'Heavy intensity rain', 'Weather description', 'jet-elements' ),
			'503' => esc_html_x( 'Very heavy rain', 'Weather description', 'jet-elements' ),
			'504' => esc_html_x( 'Extreme rain', 'Weather description', 'jet-elements' ),
			'511' => esc_html_x( 'Freezing rain', 'Weather description', 'jet-elements' ),
			'520' => esc_html_x( 'Light intensity shower rain', 'Weather description', 'jet-elements' ),
			'521' => esc_html_x( 'Shower rain', 'Weather description', 'jet-elements' ),
			'522' => esc_html_x( 'Heavy intensity shower rain', 'Weather description', 'jet-elements' ),
			'531' => esc_html_x( 'Ragged shower rain', 'Weather description', 'jet-elements' ),
			'600' => esc_html_x( 'Light snow', 'Weather description', 'jet-elements' ),
			'601' => esc_html_x( 'Snow', 'Weather description', 'jet-elements' ),
			'602' => esc_html_x( 'Heavy snow', 'Weather description', 'jet-elements' ),
			'611' => esc_html_x( 'Sleet', 'Weather description', 'jet-elements' ),
			'612' => esc_html_x( 'Light shower sleet', 'Weather description', 'jet-elements' ),
			'613' => esc_html_x( 'Shower sleet', 'Weather description', 'jet-elements' ),
			'615' => esc_html_x( 'Light rain and snow', 'Weather description', 'jet-elements' ),
			'616' => esc_html_x( 'Rain and snow', 'Weather description', 'jet-elements' ),
			'620' => esc_html_x( 'Light shower snow', 'Weather description', 'jet-elements' ),
			'621' => esc_html_x( 'Shower snow', 'Weather description', 'jet-elements' ),
			'622' => esc_html_x( 'Heavy shower snow', 'Weather description', 'jet-elements' ),
			'701' => esc_html_x( 'Mist', 'Weather description', 'jet-elements' ),
			'711' => esc_html_x( 'Smoke', 'Weather description', 'jet-elements' ),
			'721' => esc_html_x( 'Haze', 'Weather description', 'jet-elements' ),
			'731' => esc_html_x( 'Sand dust whirls', 'Weather description', 'jet-elements' ),
			'741' => esc_html_x( 'Fog', 'Weather description', 'jet-elements' ),
			'751' => esc_html_x( 'Sand', 'Weather description', 'jet-elements' ),
			'761' => esc_html_x( 'Dust', 'Weather description', 'jet-elements' ),
			'762' => esc_html_x( 'Volcanic ash', 'Weather description', 'jet-elements' ),
			'771' => esc_html_x( 'Squalls', 'Weather description', 'jet-elements' ),
			'781' => esc_html_x( 'Tornado', 'Weather description', 'jet-elements' ),
			'800' => esc_html_x( 'Clear sky', 'Weather description', 'jet-elements' ),
			'801' => esc_html_x( 'Few clouds', 'Weather description', 'jet-elements' ),
			'802' => esc_html_x( 'Scattered clouds', 'Weather description', 'jet-elements' ),
			'803' => esc_html_x( 'Broken clouds', 'Weather description', 'jet-elements' ),
			'804' => esc_html_x( 'Overcast clouds', 'Weather description', 'jet-elements' ),
		);

		$options = array();

		foreach ( $conditions as $code => $desc ) {
			$options[ $code ] = sprintf( '%1$s (%2$s)', $desc, $code );
		}

		return $options;
	}

	public function get_weather_background_media_markup() {
		$settings = $this->get_settings_for_display();
		$provider = isset( $settings['weather_api_provider'] ) ? $settings['weather_api_provider'] : 'weatherbit';
		$items_key = 'openweathermap' === $provider ? 'openweathermap_background_media_items' : 'weatherbit_background_media_items';

		if (
			empty( $settings[ $items_key ] )
		) {
			return '';
		}

		$current_code = $this->get_background_media_preview_code( $provider );

		if ( '' === $current_code && ! empty( $this->weather_data['current']['code'] ) ) {
			$current_code = (string) $this->weather_data['current']['code'];
		}

		if ( '' === $current_code ) {
			return '';
		}

		foreach ( $settings[ $items_key ] as $item ) {
			$item_codes = isset( $item['weather_codes'] ) ? (array) $item['weather_codes'] : array();
			$item_codes = array_map( 'strval', $item_codes );

			if ( empty( $item_codes ) || ! in_array( $current_code, $item_codes, true ) ) {
				continue;
			}

			return $this->get_background_media_item_markup( $item );
		}

		return '';
	}

	public function get_background_media_preview_code( $provider ) {
		if ( ! Plugin::$instance->editor->is_edit_mode() ) {
			return '';
		}
		$settings    = $this->get_settings_for_display();
		$setting_key = 'openweathermap' === $provider ? 'openweathermap_background_media_preview_code' : 'weatherbit_background_media_preview_code';

		if ( empty( $settings[ $setting_key ] ) ) {
			return '';
		}

		return (string) $settings[ $setting_key ];
	}

	public function get_background_media_item_markup( $item ) {
		$media_type = isset( $item['media_type'] ) ? $item['media_type'] : 'image';
		$video      = isset( $item['background_video'] ) ? $item['background_video'] : array();

		if ( 'video' === $media_type && ! empty( $video['url'] ) ) {
			return sprintf(
				'<div class="jet-weather__media" aria-hidden="true"><video class="jet-weather__media-video" autoplay muted loop playsinline preload="metadata"><source src="%1$s" /></video></div>',
				esc_url( $video['url'] )
			);
		}

		$image = isset( $item['background_image'] ) ? $item['background_image'] : array();

		if ( 'image' !== $media_type || empty( $image['url'] ) ) {
			return '';
		}

		return sprintf(
			'<div class="jet-weather__media" aria-hidden="true"><img class="jet-weather__media-image" src="%1$s" alt="" /></div>',
			esc_url( $image['url'] )
		);
	}

	public function normalize_owm_data( $current_data = [], $forecast_data = [] ) {
		$current_timezone  = isset( $current_data['timezone'] ) ? (int) $current_data['timezone'] : 0;
		$forecast_timezone = isset( $forecast_data['city']['timezone'] ) ? (int) $forecast_data['city']['timezone'] : $current_timezone;
		$current_hour      = (int) gmdate( 'H', $current_data['dt'] + $current_timezone );

		$current = [
			'code'       => $current_data['weather'][0]['id'],
			'is_day'     => $current_hour >= 6 && $current_hour < 18,
			'temp'       => $current_data['main']['temp'],
			'temp_min'   => null,
			'temp_max'   => null,
			'wind_speed' => $current_data['wind']['speed'],
			'wind_deg'   => $current_data['wind']['deg'],
			'wind_dir'   => $this->deg_to_compass( $current_data['wind']['deg'] ),
			'humidity'   => $current_data['main']['humidity'] . '%',
			'pressure'   => $current_data['main']['pressure'],
			'sunrise'    => gmdate( 'H:i', $current_data['sys']['sunrise'] + $current_timezone ),
			'sunset'     => gmdate( 'H:i', $current_data['sys']['sunset'] + $current_timezone ),
		];
	
		$location = [
			'city'    => $current_data['name'],
			'country' => $current_data['sys']['country'],
		];
	
		$forecast = [];
		if ( !empty( $forecast_data['list'] ) && is_array( $forecast_data['list'] )) {
			$days = [];
			foreach ( $forecast_data['list'] as $entry ) {
				$date = gmdate( 'Y-m-d', $entry['dt'] + $forecast_timezone );
				if ( !isset( $days[$date] )) {
					$days[$date] = [
						'temp_min' => $entry['main']['temp_min'],
						'temp_max' => $entry['main']['temp_max'],
						'code'     => $entry['weather'][0]['id'],
					];
				} else {
					$days[$date]['temp_min'] = min( $days[$date]['temp_min'], $entry['main']['temp_min'] );
					$days[$date]['temp_max'] = max( $days[$date]['temp_max'], $entry['main']['temp_max'] );
				}
			}
	
			foreach ( $days as $date => $data ) {
				$forecast[] = array_merge( ['date' => $date], $data );
			}
	
			$current['temp_min'] = $forecast[0]['temp_min'];
			$current['temp_max'] = $forecast[0]['temp_max'];
		}
	
		return compact( 'location', 'current', 'forecast' );
	}
	
	private function deg_to_compass( $deg ) {
		$val = floor((( $deg / 22.5) + 0.5 ));
		$directions = ['N','NNE','NE','ENE','E','ESE','SE','SSE','S','SSW','SW','WSW','W','WNW','NW','NNW'];
		return $directions[ $val % 16 ];
	}

	/**
	 * Get weather conditions by weather code.
	 *
	 * @param int    $code      Weather code.
	 * @param string $condition Weather condition: 'desc' or 'icon'.
	 * @param bool   $is_day    Is day.
	 *
	 * @return array|bool|string|int
	 */
	public function get_weather_conditions( $code = null, $condition = null, $is_day = true ) {

		$conditions = apply_filters( 'jet-elements/weather/conditions', array(
			// Thunderstorm
			'200' => array(
				'desc' => esc_html_x( 'Thunderstorm with light rain', 'Weather description', 'jet-elements' ),
				'icon' => 1,
			),
			'201' => array(
				'desc' => esc_html_x( 'Thunderstorm with rain', 'Weather description', 'jet-elements' ),
				'icon' => 1,
			),
			'202' => array(
				'desc' => esc_html_x( 'Thunderstorm with heavy rain', 'Weather description', 'jet-elements' ),
				'icon' => 1,
			),
			'210' => array(
				'desc' => esc_html_x( 'Light thunderstorm', 'Weather description', 'jet-elements' ),
				'icon' => 1,
			),
			'211' => array(
				'desc' => esc_html_x( 'Thunderstorm', 'Weather description', 'jet-elements' ),
				'icon' => 1,
			),
			'212' => array(
				'desc' => esc_html_x( 'Heavy thunderstorm', 'Weather description', 'jet-elements' ),
				'icon' => 1,
			),
			'221' => array(
				'desc' => esc_html_x( 'Ragged thunderstorm', 'Weather description', 'jet-elements' ),
				'icon' => 1,
			),
			'230' => array(
				'desc' => esc_html_x( 'Thunderstorm with light drizzle', 'Weather description', 'jet-elements' ),
				'icon' => 2,
			),
			'231' => array(
				'desc' => esc_html_x( 'Thunderstorm with drizzle', 'Weather description', 'jet-elements' ),
				'icon' => 2,
			),
			'232' => array(
				'desc' => esc_html_x( 'Thunderstorm with heavy drizzle', 'Weather description', 'jet-elements' ),
				'icon' => 2,
			),
			'233' => array(
				'desc' => esc_html_x( 'Thunderstorm with Hail', 'Weather description', 'jet-elements' ),
				'icon' => 2,
			),

			// Drizzle
			'300' => array(
				'desc' => esc_html_x( 'Light Drizzle', 'Weather description', 'jet-elements' ),
				'icon' => 3,
			),
			'301' => array(
				'desc' => esc_html_x( 'Drizzle', 'Weather description', 'jet-elements' ),
				'icon' => 3,
			),
			'302' => array(
				'desc' => esc_html_x( 'Heavy Drizzle', 'Weather description', 'jet-elements' ),
				'icon' => 3,
			),
			'310' => array(
				'desc' => esc_html_x( 'Light intensity drizzle rain', 'Weather description', 'jet-elements' ),
				'icon' => 3,
			),
			'311' => array(
				'desc' => esc_html_x( 'Drizzle rain', 'Weather description', 'jet-elements' ),
				'icon' => 3,
			),
			'312' => array(
				'desc' => esc_html_x( 'Heavy intensity drizzle rain', 'Weather description', 'jet-elements' ),
				'icon' => 3,
			),
			'313' => array(
				'desc' => esc_html_x( 'Shower rain and drizzle', 'Weather description', 'jet-elements' ),
				'icon' => 3,
			),
			'314' => array(
				'desc' => esc_html_x( 'Heavy shower rain and drizzle', 'Weather description', 'jet-elements' ),
				'icon' => 4,
			),
			'321' => array(
				'desc' => esc_html_x( 'Shower drizzle', 'Weather description', 'jet-elements' ),
				'icon' => 3,
			),

			// Rain
			'500' => array(
				'desc' => esc_html_x( 'Light Rain', 'Weather description', 'jet-elements' ),
				'icon' => 3,
			),
			'501' => array(
				'desc' => esc_html_x( 'Moderate Rain', 'Weather description', 'jet-elements' ),
				'icon' => 3,
			),
			'502' => array(
				'desc' => esc_html_x( 'Heavy Rain', 'Weather description', 'jet-elements' ),
				'icon' => 4,
			),
			'503' => array(
				'desc' => esc_html_x( 'Very heavy rain', 'Weather description', 'jet-elements' ),
				'icon' => 4,
			),
			'504' => array(
				'desc' => esc_html_x( 'Extreme rain', 'Weather description', 'jet-elements' ),
				'icon' => 5,
			),
			'511' => array(
				'desc' => esc_html_x( 'Freezing rain', 'Weather description', 'jet-elements' ),
				'icon' => 9,
			),
			'520' => array(
				'desc' => esc_html_x( 'Light shower rain', 'Weather description', 'jet-elements' ),
				'icon' => 3,
			),
			'521' => array(
				'desc' => esc_html_x( 'Shower rain', 'Weather description', 'jet-elements' ),
				'icon' => 4,
			),
			'522' => array(
				'desc' => esc_html_x( 'Heavy shower rain', 'Weather description', 'jet-elements' ),
				'icon' => 5,
			),
			'531' => array(
				'desc' => esc_html_x( 'Ragged shower rain', 'Weather description', 'jet-elements' ),
				'icon' => 4,
			),

			// Snow
			'600' => array(
				'desc' => esc_html_x( 'Light snow', 'Weather description', 'jet-elements' ),
				'icon' => $is_day ? 6 : 7,
			),
			'601' => array(
				'desc' => esc_html_x( 'Snow', 'Weather description', 'jet-elements' ),
				'icon' => 7,
			),
			'602' => array(
				'desc' => esc_html_x( 'Heavy Snow', 'Weather description', 'jet-elements' ),
				'icon' => 8,
			),
			'610' => array(
				'desc' => esc_html_x( 'Mix snow/rain', 'Weather description', 'jet-elements' ),
				'icon' => 9,
			),
			'611' => array(
				'desc' => esc_html_x( 'Sleet', 'Weather description', 'jet-elements' ),
				'icon' => 10,
			),
			'612' => array(
				'desc' => esc_html_x( 'Heavy sleet', 'Weather description', 'jet-elements' ),
				'icon' => 10,
			),
			'613' => array(
				'desc' => esc_html_x( 'Shower sleet', 'Weather description', 'jet-elements' ),
				'icon' => 10,
			),
			'615' => array(
				'desc' => esc_html_x( 'Light rain and snow', 'Weather description', 'jet-elements' ),
				'icon' => 9,
			),
			'616' => array(
				'desc' => esc_html_x( 'Rain and snow', 'Weather description', 'jet-elements' ),
				'icon' => 9,
			),
			'620' => array(
				'desc' => esc_html_x( 'Light shower snow', 'Weather description', 'jet-elements' ),
				'icon' => 7,
			),
			'621' => array(
				'desc' => esc_html_x( 'Snow shower', 'Weather description', 'jet-elements' ),
				'icon' => 7,
			),
			'622' => array(
				'desc' => esc_html_x( 'Heavy snow shower', 'Weather description', 'jet-elements' ),
				'icon' => 11,
			),
			'623' => array(
				'desc' => esc_html_x( 'Flurries', 'Weather description', 'jet-elements' ),
				'icon' => 7,
			),

			// Special
			'701' => array(
				'desc' => esc_html_x( 'Mist', 'Weather description', 'jet-elements' ),
				'icon' => 12,
			),
			'700' => array(
				'desc' => esc_html_x( 'Mist', 'Weather description', 'jet-elements' ),
				'icon' => 12,
			),
			'711' => array(
				'desc' => esc_html_x( 'Smoke', 'Weather description', 'jet-elements' ),
				'icon' => 13,
			),
			'721' => array(
				'desc' => esc_html_x( 'Haze', 'Weather description', 'jet-elements' ),
				'icon' => 12,
			),
			'731' => array(
				'desc' => esc_html_x( 'Sand/dust', 'Weather description', 'jet-elements' ),
				'icon' => 14,
			),
			'741' => array(
				'desc' => esc_html_x( 'Fog', 'Weather description', 'jet-elements' ),
				'icon' => 15,
			),
			'751' => array(
				'desc' => esc_html_x( 'Freezing Fog', 'Weather description', 'jet-elements' ),
				'icon' => 15,
			),
			'761' => array(
				'desc' => esc_html_x( 'Dust', 'Weather description', 'jet-elements' ),
				'icon' => 14,
			),
			'762' => array(
				'desc' => esc_html_x( 'Volcanic ash', 'Weather description', 'jet-elements' ),
				'icon' => 14,
			),
			'771' => array(
				'desc' => esc_html_x( 'Squalls', 'Weather description', 'jet-elements' ),
				'icon' => 14,
			),
			'781' => array(
				'desc' => esc_html_x( 'Tornado', 'Weather description', 'jet-elements' ),
				'icon' => 14,
			),

			// Clouds
			'800' => array(
				'desc' => esc_html_x( 'Clear sky', 'Weather description', 'jet-elements' ),
				'icon' => $is_day ? 16 : 17,
			),
			'801' => array(
				'desc' => esc_html_x( 'Few clouds', 'Weather description', 'jet-elements' ),
				'icon' => $is_day ? 18 : 17,
			),
			'802' => array(
				'desc' => esc_html_x( 'Scattered clouds', 'Weather description', 'jet-elements' ),
				'icon' => $is_day ? 18 : 17,
			),
			'803' => array(
				'desc' => esc_html_x( 'Broken clouds', 'Weather description', 'jet-elements' ),
				'icon' => 19,
			),
			'804' => array(
				'desc' => esc_html_x( 'Overcast clouds', 'Weather description', 'jet-elements' ),
				'icon' => 19,
			),
			'900' => array(
				'desc' => esc_html_x( 'Unknown Precipitation', 'Weather description', 'jet-elements' ),
				'icon' => 3,
			),
		) );

		if ( ! $code ) {
			return $conditions;
		}

		$code_key = (string) $code;

		if ( ! isset( $conditions[ $code_key ] ) ) {
			return false;
		}

		if ( $condition && isset( $conditions[ $code_key ][ $condition ] ) ) {
			return $conditions[ $code_key ][ $condition ];
		}

		return $conditions[ $code_key ];
	}

	/**
	 * Get weather description.
	 *
	 * @param int  $code   Weather code.
	 * @param bool $is_day Is day.
	 *
	 * @return string
	 */
	public function get_weather_desc( $code, $is_day = true ) {

		if ( ! $code ) {
			return '';
		}

		$desc = $this->get_weather_conditions( $code, 'desc', $is_day );

		if ( empty( $desc ) ) {
			return '';
		}

		return $desc;
	}

	/**
	 * Get week day from date.
	 *
	 * @param string $date Date.
	 *
	 * @return bool|string
	 */
	public function get_week_day_from_date( $date = '' ) {
		return date_i18n( 'l', strtotime( $date ) );
	}

	/**
	 * Get title html markup.
	 *
	 * @return string
	 */
	public function get_weather_title() {
		$settings   = $this->get_settings_for_display();
		$show_title = isset( $settings['show_title'] ) ? $settings['show_title'] : 'true';

		if ( ! filter_var( $show_title, FILTER_VALIDATE_BOOLEAN ) ) {
			return '';
		}

		$type = isset( $settings['title_type'] ) ? $settings['title_type'] : 'api';
		$tag  = isset( $settings['title_size'] ) ? jet_elements_tools()->validate_html_tag( $settings['title_size'] ) : 'h3';

		switch ( $type ) {
			case 'location':
				$location_type = isset( $settings['location_type'] ) ? $settings['location_type'] : 'city';
				
				if ( 'coordinates' === $location_type ) {					
					$title = esc_html( $settings['coordinates'] );
				} else {					
					$title = esc_html( $settings['location'] );
				}
				break;

			case 'custom':
				$title = esc_html( $settings['custom_title'] );
				break;

			default:
				$title = $this->weather_data['location']['city'];
		}

		if ( isset( $settings['show_country_name'] ) && 'true' === $settings['show_country_name'] ) {
			$country = $this->weather_data['location']['country'];

			$title = sprintf( '%1$s, %2$s', $title, $country );
		}

		return sprintf( '<%1$s class="jet-weather__title">%2$s</%1$s>', $tag, $title );
	}

	/**
	 * Get temperature html markup.
	 *
	 * @param int|array $temp Temperature value.
	 *
	 * @return string
	 */
	public function get_weather_temp( $temp ) {
		$units     = $this->get_settings_for_display( 'units' );
		$temp_unit = ( 'metric' === $units ) ? '&#176;C' : '&#176;F';
	
		// For 2.0 API Count
		if ( is_array( $temp ) ) {
			$temp = ( 'metric' === $units ) ? $temp['c'] : $temp['f'];
		}

		$temp = floatval( $temp );
		$format = apply_filters( 'jet-elements/weather/temperature-format', '%1$s%2$s' );
	
		return sprintf( $format, round( $temp ), $temp_unit );
	}

	/**
	 * Get wind.
	 *
	 * @param int|array  $speed Wind speed.
	 * @param int|string $deg   Wind direction, degrees.
	 *
	 * @return string
	 */
	public function get_wind( $speed, $deg ) {
		$units      = $this->get_settings_for_display( 'units' );
		$speed_unit = ( 'metric' === $units ) ? esc_html_x( 'm/s', 'Unit of speed (meters/second)', 'jet-elements' ) : esc_html_x( 'mph', 'Unit of speed (miles per hour)', 'jet-elements' );

		// For 2.0 API Count
		if ( is_array( $speed ) ) {
			$speed = ( 'metric' === $units ) ? $speed['kph'] : $speed['mph'];
		}

		$direction = '';

		if ( ! is_numeric( $deg ) ) {
			$direction = $deg;
		} else {
			if ( ( $deg >= 0 && $deg <= 11.25 ) || ( $deg > 348.75 && $deg <= 360 ) ) {
				$direction = esc_html_x( 'N', 'Wind direction', 'jet-elements' );
			} else if ( $deg > 11.25 && $deg <= 33.75 ) {
				$direction = esc_html_x( 'NNE', 'Wind direction', 'jet-elements' );
			} else if ( $deg > 33.75 && $deg <= 56.25 ) {
				$direction = esc_html_x( 'NE', 'Wind direction', 'jet-elements' );
			} else if ( $deg > 56.25 && $deg <= 78.75 ) {
				$direction = esc_html_x( 'ENE', 'Wind direction', 'jet-elements' );
			} else if ( $deg > 78.75 && $deg <= 101.25 ) {
				$direction = esc_html_x( 'E', 'Wind direction', 'jet-elements' );
			} else if ( $deg > 101.25 && $deg <= 123.75 ) {
				$direction = esc_html_x( 'ESE', 'Wind direction', 'jet-elements' );
			} else if ( $deg > 123.75 && $deg <= 146.25 ) {
				$direction = esc_html_x( 'SE', 'Wind direction', 'jet-elements' );
			} else if ( $deg > 146.25 && $deg <= 168.75 ) {
				$direction = esc_html_x( 'SSE', 'Wind direction', 'jet-elements' );
			} else if ( $deg > 168.75 && $deg <= 191.25 ) {
				$direction = esc_html_x( 'S', 'Wind direction', 'jet-elements' );
			} else if ( $deg > 191.25 && $deg <= 213.75 ) {
				$direction = esc_html_x( 'SSW', 'Wind direction', 'jet-elements' );
			} else if ( $deg > 213.75 && $deg <= 236.25 ) {
				$direction = esc_html_x( 'SW', 'Wind direction', 'jet-elements' );
			} else if ( $deg > 236.25 && $deg <= 258.75 ) {
				$direction = esc_html_x( 'WSW', 'Wind direction', 'jet-elements' );
			} else if ( $deg > 258.75 && $deg <= 281.25 ) {
				$direction = esc_html_x( 'W', 'Wind direction', 'jet-elements' );
			} else if ( $deg > 281.25 && $deg <= 303.75 ) {
				$direction = esc_html_x( 'WNW', 'Wind direction', 'jet-elements' );
			} else if ( $deg > 303.75 && $deg <= 326.25 ) {
				$direction = esc_html_x( 'NW', 'Wind direction', 'jet-elements' );
			} else if ( $deg > 326.25 && $deg <= 348.75 ) {
				$direction = esc_html_x( 'NNW', 'Wind direction', 'jet-elements' );
			}
		}

		$format = apply_filters( 'jet-elements/weather/wind-format', '%1$s %2$s %3$s' );

		return sprintf( $format, $direction, round( $speed ), $speed_unit );
	}

	/**
	 * Get weather pressure.
	 *
	 * @param int|array $pressure Pressure value.
	 *
	 * @return string
	 */
	public function get_weather_pressure( $pressure ) {
		$units = $this->get_settings_for_display( 'units' );

		// For 2.0 API Count
		if ( is_array( $pressure ) ) {
			$pressure = ( 'metric' === $units ) ? $pressure['mb'] : $pressure['in'];
		}

		$format = apply_filters( 'jet-elements/weather/pressure-format', '%s' );

		return sprintf( $format, round( $pressure ) );
	}

	/**
	 * Get weather astro time.
	 *
	 * @param  string $time
	 * @return string
	 */

	public function get_weather_astro_time( $time ) {
		$format         = $this->get_settings_for_display( 'time_format' );
		$current_offset = $this->get_settings_for_display( 'show_current_weather_utc' );
		$gmt_offset     = get_option('gmt_offset', 0);
		$current_time   = strtotime( $time);

		if ( $current_offset ) {
			$current_time   = strtotime( $time . "+{$gmt_offset}hours");
		}

		$time = date('H:i', $current_time);

		if ( '12' === $format ) {
			$time = date( 'h:i A', $current_time);
		}

		return $time;
	}

	/**
	 * Get weather notice html markup.
	 *
	 * @param string $message Message.
	 *
	 * @return string
	 */
	public function get_weather_notice( $message ) {
		return sprintf( '<div class="jet-weather-notice">%s</div>', $message );
	}

	/**
	 * Get weather svg icon.
	 *
	 * @param string|int $icon            Icon slug or weather code.
	 * @param bool       $is_weather_code Is weather code.
	 * @param bool       $is_day          Is day.
	 *
	 * @return bool|string
	 */
	public function get_weather_svg_icon( $icon, $is_weather_code = false, $is_day = true ) {

		if ( ! $icon ) {
			return false;
		}

		if ( $is_weather_code ) {
			$icon = $this->get_weather_conditions( $icon, 'icon', $is_day );
		}

		$icon_path = jet_elements()->plugin_path( "assets/images/weather-icons/{$icon}.svg" );

		if ( ! file_exists( $icon_path ) ) {
			return false;
		}

		ob_start();

		include $icon_path;

		$svg = ob_get_clean();

		$_classes   = array();
		$_classes[] = 'jet-weather-icon';
		$_classes[] = sprintf( 'jet-weather-icon-%s', esc_attr( $icon ) );

		$classes = join( ' ', $_classes );

		return sprintf( '<div class="%2$s">%1$s</div>', $svg, $classes );
	}
}
