<?php

namespace FlexiMenu\Frontend;

defined( 'ABSPATH' ) || exit;

class MenuMaker {

	private $id;
	private $param;

	public function __construct( $id, $param ) {
		$this->id    = $id;
		$this->param = $param;

	}

	public function init(): string {

		$count = ! empty( $this->param['item']['type'] ) ? count( $this->param['item']['type'] ) : 0;

		if ( $count === 0 ) {
			return false;
		}

		$menu = $this->create_box( 'start' );
		$menu .= $this->create_menu( 'start' );
		$menu .= $this->create_items( $count );

		$menu .= $this->create_menu( 'end' );
		$menu .= $this->create_box( 'end' );
		$menu .= $this->create_dialog( $count );

		return $menu;
	}

	private function create_box( $part ): string {
		$out = '';
		if ( $part === 'start' ) {
			$out .= '<div class="fleximenu-box';
			$out .= $this->box_classes();
			$out .= $this->position();
			$out .= '"';
			$out .= $this->get_style();
			$out .= $this->options();
			$out .= '>';
		}

		if ( $part === 'end' ) {
			$out .= '</div>';
		}

		return $out;
	}

	private function box_classes(): string {
		$param = $this->param;
		$out   = '';

		$classes = [
			'menu_shadow'         => '-shadow',
			'include_menu_radius' => '-rounded',
			'include_menu_min_w'  => '-min-width',
			'icon_shadow'         => '-icon-shadow',
		];

		foreach ( $classes as $key => $class ) {
			if ( ! empty( $param[ $key ] ) ) {
				$out .= " $class";
			}
		}

		return $out;
	}

	private function position(): string {
		$out      = '';
		$type     = ! empty( $this->param['menu_type'] ) ? $this->param['menu_type'] : 'floating';
		$position = ! empty( $this->param['menu_position'] ) ? $this->param['menu_position'] : '-left';
		if ( $type === 'floating' ) {
			$out = ' ' . esc_attr( $position );
		} elseif ( $type === 'static' ) {
			$out = ' -static';
		} elseif ( $type === 'attached' ) {
			$out = ' -absolute ' . esc_attr( $position );
			if ( ! empty( $this->param['menu_out'] ) ) {
				$out .= ' -out';
			}
		}

		return $out;
	}

	private function options(): string {
		$param        = $this->param;
		$data         = [];
		$out          = ' data-fleximenu="';
		$data['type'] = $param['menu_type'] ?? 'floating';

		switch ( $data['type'] ) {
			case 'floating':
			case 'static':
				$data['trigger'] = 'load';
				break;
			case 'context':
				$data['trigger']    = 'contextmenu';
				$data['triggerOut'] = 'mousedown';
				break;
			case 'selectText':
				$data['trigger']    = 'mouseup';
				$data['triggerOut'] = [ 'mousedown', 'scroll', 'esc' ];
				break;
			case 'popover':
				$data['trigger']    = 'mouseup';
				$data['triggerOut'] = [ 'mousedown', 'scroll', 'esc' ];
				$data['target']     = $param['menu_selector'] ?? '';
				break;

			case 'dropdown':
				$data['trigger']    = $param['menu_action'] ?? 'click';
				$data['triggerOut'] = [ 'mousedown', 'scroll', 'esc' ];
				$data['target']     = $param['menu_selector'] ?? '';
				break;
			case 'attached':
				$data['trigger']  = 'load';
				$data['position'] = [
					'sel' => $param['menu_selector'] ?? '',
					'loc' => $param['menu_position'] ?? '-left',
					'out' => ! empty( $param['menu_out'] ),
				];
				break;
		}


		$out .= esc_attr( wp_json_encode( $data ) );
		$out .= '"';

		return $out;
	}

	private function create_menu( $part ): string {
		$out = '';
		if ( $part === 'start' ) {
			$out .= '<ul class="fleximenu';
			$out .= $this->get_menu_classes();
			$out .= '"';

			$out .= '>';
		}
		if ( $part === 'end' ) {
			$out .= '</ul>';
		}

		return $out;
	}

	private function get_menu_classes(): string {
		$param   = $this->param;
		$classes = [
			'menu_inline'  => 'fleximenu--inline',
			'menu_icon'    => 'fleximenu--icon',
			'menu_reverse' => '-reverse',
		];

		$out = '';

		foreach ( $classes as $key => $class ) {
			if ( ! empty( $param[ $key ] ) ) {
				$out .= ' ' . $class;
			}
		}

		if ( $param['menu_type'] === 'floating' && ! empty( $param['menu_icon'] ) && ( $param['menu_position'] === '-right' || $param['menu_position'] === '-right-bottom' || $param['menu_position'] === '-right-top' ) ) {
			$out .= ' -label-opposite';
		}

		return $out;
	}

	private function get_style(): string {
		$out = '';

		$args = [
			'menu_bg'              => '#ffffff',
			'menu_radius'          => '4',
			'items_gap'            => '0',
			'submenu_offset'       => '8',
			'menu_padding_block'   => '8',
			'menu_padding_inline'  => '0',
			'menu_offset_block'    => '0',
			'menu_offset_inline'   => '0',
			'menu_min_w'           => '160',
			'link_padding_inline'  => '16',
			'link_padding_block'   => '8',
			'link_gap'             => '8',
			'link_hover_bg'        => '#F3F4F6',
			'icon_size'            => '16',
			'icon_box'             => '16',
			'icon_color'           => '#383838',
			'icon_bg'              => 'rgba(255, 255, 255, 0)',
			'label_size'           => '16',
			'label_color'          => '#383838',
			'label_padding_inline' => '0',
			'label_padding_block'  => '0',
			'label_weight'         => '400',
			'label_style'          => 'normal',
		];

		foreach ( $args as $key => $default ) {
			$out .= $this->get_param( $key, $default );
		}

		if ( ! empty( $out ) ) {
			$out = ' style="' . esc_attr( $out ) . '"';
		}

		return $out;
	}

	private function get_param( $key, $default ): string {
		$params = $this->param;
		$prefix = '--flexi-';

		if ( isset( $params[ $key ] ) && $params[ $key ] !== $default ) {
			$value = esc_attr( $params[ $key ] );

			return sprintf( '%s%s: %s;', $prefix, $key, $value );
		}

		return '';
	}

	private function create_items( $count ): string {
		$param = $this->param;
		$out   = '';

		for ( $i = 0; $i < $count; $i ++ ) {
			$type = $param['item']['type'][ $i ] ?? '';
			if ( $type === 'next_post' ) {
				$next_post = get_next_post( true );
				if ( empty( $next_post ) ) {
					continue;
				}

			} elseif ( $type === 'previous_post' ) {
				$previous_post = get_previous_post( true );
				if ( empty( $previous_post ) ) {
					continue;
				}
			} elseif ( $type === 'goback' ) {
				if ( empty( $_SERVER['HTTP_REFERER'] ) ) {
					continue;
				}
			} elseif ( ( $type === 'login' || $type === 'lostpassword' || $type === 'register' ) && is_user_logged_in() ) {
				continue;
			} elseif ( $type === 'logout' && ! is_user_logged_in() ) {
				continue;
			}

			$sub      = ! empty( $param['item_parent'][ $i ] ) ? absint( $param['item_parent'][ $i ] ) : 0;
			$next_i   = $i + 1;
			$next_sub = ! empty( $param['item_parent'][ $next_i ] ) ? absint( $param['item_parent'][ $next_i ] ) : 0;

			$out .= $this->create_item( $i, $sub, $next_sub );
		}

		return $out;
	}

	private function create_item( $i, $sub, $next_sub ): string {
		$item = $this->create_link( $i );

		if ( ( $sub === 0 && $next_sub === 1 ) || ( $sub === 1 && $next_sub === 2 ) ) {
			return "<li class='fleximenu-item fleximenu-item--has-sub'>
                    {$item}
                    <ul class='fleximenu-sub'>";
		}

		if ( ( $sub === 1 && $next_sub === 0 ) || ( $sub === 2 && $next_sub === 1 ) ) {
			return "<li class='fleximenu-item'>
                    {$item}</li>
                </ul></li>";
		}

		if ( $sub === 2 && $next_sub === 0 ) {
			return "<li class='fleximenu-item'>
                    {$item}</li>
                </ul></li></ul>";
		}

		return "<li class='fleximenu-item'>{$item}</li>";
	}


	private function create_link( $i ): string {
		$class = ! empty( $this->param['item']['attribute_class'][ $i ] ) ? ' ' . $this->param['item']['attribute_class'][ $i ] : '';
		$id    = ! empty( $this->param['item']['attribute_id'][ $i ] ) ? $this->param['item']['attribute_id'][ $i ] : '';
		$rel   = ! empty( $this->param['item']['attribute_rel'][ $i ] ) ? $this->param['item']['attribute_rel'][ $i ] : '';

		$out = '<a';
		$out .= ! empty( $id ) ? ' id="' . esc_attr( $id ) . '"' : '';
		$out .= ' class="fleximenu-link' . esc_attr( $class ) . '"';
		$out .= ! empty( $rel ) ? ' rel="' . esc_attr( $rel ) . '"' : '';
		$out .= $this->create_action( $i );
		$out .= '>';
		$out .= $this->create_icon( $i );
		$out .= $this->create_label( $i );
		$out .= '</a>';

		return $out;
	}

	private function create_action( $i ): string {
		$param  = $this->param['item'];
		$type   = $param['type'][ $i ] ?? 'link';
		$target = ! empty( $param['_blank'][ $i ] ) ? '_blank' : '_self';

		$out = '';

		switch ( $type ) {
			//region Links
			case 'link':
				$link        = ! empty( $param['link'][ $i ] ) ? $param['link'][ $i ] : '#';
				$out         .= 'href="' . esc_attr( $link ) . '" target="' . esc_attr( $target ) . '"';
				$interaction = $this->add_tracking( $i );
				if ( ! empty( $interaction ) ) {
					$out .= ' data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				}
				break;
			case 'login':
			case 'logout':
			case 'lostpassword':
				$redirect    = ! empty( $param['link'][ $i ] ) ? $param['link'][ $i ] : '#';
				$link        = call_user_func( 'wp_' . $type . '_url', $redirect );
				$out         .= 'href="' . esc_url( $link ) . '" target="' . esc_attr( $target ) . '"';
				$interaction = $this->add_tracking( $i );
				if ( ! empty( $interaction ) ) {
					$out .= ' data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				}
				break;
			case 'register':
				$link        = wp_registration_url();
				$out         .= 'href="' . esc_url( $link ) . '" target="' . esc_attr( $target ) . '"';
				$interaction = $this->add_tracking( $i );
				if ( ! empty( $interaction ) ) {
					$out .= ' data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				}
				break;
			case 'goback':
				$link        = ! empty( $_SERVER['HTTP_REFERER'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : home_url();
				$out         .= 'href="' . esc_url( $link ) . '" target="' . esc_attr( $target ) . '"';
				$interaction = $this->add_tracking( $i );
				if ( ! empty( $interaction ) ) {
					$out .= ' data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				}
				break;
			case 'next_post':
				$next_post   = get_next_post( true );
				$link        = get_permalink( $next_post );
				$out         .= 'href="' . esc_url( $link ) . '" target="' . esc_attr( $target ) . '"';
				$interaction = $this->add_tracking( $i );
				if ( ! empty( $interaction ) ) {
					$out .= ' data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				}
				break;
			case 'previous_post':
				$previous_post = get_previous_post( true );
				$link          = get_permalink( $previous_post );
				$out           .= 'href="' . esc_url( $link ) . '" target="' . esc_attr( $target ) . '"';
				$interaction   = $this->add_tracking( $i );
				if ( ! empty( $interaction ) ) {
					$out .= ' data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				}
				break;
			case 'email':
				$email = $param['link'][ $i ];
				$link  = is_email( $email ) ? 'mailto:' . antispambot( $email ) : $email;
				$out   .= 'href="' . esc_attr( $link ) . '" target="' . esc_attr( $target ) . '"';
				break;
			case 'telephone':
				$link        = ! empty( $param['link'][ $i ] ) ? $param['link'][ $i ] : '#';
				$out         .= 'href="tel:' . esc_attr( $link ) . '" target="' . esc_attr( $target ) . '"';
				$interaction = $this->add_tracking( $i );
				if ( ! empty( $interaction ) ) {
					$out .= ' data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				}
				break;
			//endregion
			//region Actions
			case 'google_translate':
				$lang        = $param['translate'][ $i ];
				$current_url = $this->_get_current_url();
				$link        = 'https://translate.google.com/translate?hl=&sl=auto&tl=' . $lang . '&u=' . urlencode( $current_url );
				$out         .= 'href="' . esc_url( $link ) . '" target="' . esc_attr( $target ) . '"';
				$interaction = $this->add_tracking( $i );
				if ( ! empty( $interaction ) ) {
					$out .= ' data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				}
				break;
			case 'download':
				$link     = ! empty( $param['link'][ $i ] ) ? $param['link'][ $i ] : '#';
				$download = ! empty( $param['download'][ $i ] ) ? $param['download'][ $i ] : '';
				$out      .= 'href="' . esc_url( $link ) . '" download="' . esc_attr( $download ) . '"';
				break;
			case 'share':
				$share       = ! empty( $param['share'][ $i ] ) ? $param['share'][ $i ] : '';
				$interaction = 'share:' . esc_attr( $share );
				$interaction .= $this->add_tracking( $i );
				$out         .= 'href="#" data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				break;
			case 'share_text':
				$share       = ! empty( $param['share_text'][ $i ] ) ? $param['share_text'][ $i ] : '';
				$interaction = 'share:' . esc_attr( $share ) . ' text';
				$interaction .= $this->add_tracking( $i );
				$out         .= 'href="#" data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				break;
			case 'translate':
				$lang        = $param['translate'][ $i ];
				$out         .= 'href="#" data-flexi-translate="' . esc_attr( $lang ) . '"';
				$interaction = $this->add_tracking( $i );
				if ( ! empty( $interaction ) ) {
					$out .= ' data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				}
				break;
			case 'print':
				$interaction = 'bookmark';
				$interaction .= $this->add_tracking( $i );
				$out         .= 'href="#" data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				break;
			case 'bookmark':
				$interaction = 'bookmark';
				$interaction .= ! empty( $param['mess'][ $i ] ) ? ' mess:(' . $param['mess'][ $i ] . ')' : '';
				$interaction .= $this->add_tracking( $i );
				$out         .= 'href="#" data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				break;
			case 'dialog':
				$dialogId    = 'flexiMenuDialog_' . $this->id . '_' . $i;
				$interaction = 'dialog:' . $dialogId . ' open';
				$interaction .= $this->add_tracking( $i );
				$out         .= 'href="#" data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				break;
			//region Copy
			case 'copyUrl':
				$interaction = 'copy:url';
				$interaction .= ! empty( $param['mess'][ $i ] ) ? ' mess:(' . $param['mess'][ $i ] . ')' : '';
				$interaction .= $this->add_tracking( $i );
				$out         .= 'href="#" data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				break;
			case 'copyText':
				$interaction = 'copy:text';
				$interaction .= ! empty( $param['mess'][ $i ] ) ? ' mess:(' . $param['mess'][ $i ] . ')' : '';
				$interaction .= $this->add_tracking( $i );
				$out         .= 'href="#" data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				break;
			//endregion
			//region Scroll
			case 'totop':
				$interaction = 'scroll:top';
				$interaction .= $this->add_tracking( $i );
				$out         .= 'href="#" data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				break;
			case 'tobottom':
				$interaction = 'scroll:bottom';
				$interaction .= $this->add_tracking( $i );
				$out         .= 'href="#" data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				break;
			case 'smoothscroll':
				$link = ! empty( $param['link'][ $i ] ) ? $param['link'][ $i ] : '#';
				if ( strpos( $link, '#' ) === false ) {
					$link = '#' . $link;
				}
				$interaction = 'scroll:{sel:' . $link . '}';
				$interaction .= $this->add_tracking( $i );
				$out         .= 'href="#" data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				break;
			//endregion
			//region Media
			case 'play':
			case 'pause':
			case 'muted':
			case 'loop':
			case 'reset':
			case 'volumeUp':
			case 'volumeDown':
				$sel         = ! empty( $param['link'][ $i ] ) ? $param['link'][ $i ] : '';
				$interaction = 'media:{type:' . esc_attr( $type ) . ' sel:(' . esc_attr( $sel ) . ')}';
				$interaction .= $this->add_tracking( $i );
				$out         .= 'href="#" data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				break;
			//endregion
			//region JS Actions
			case 'function':
				$link        = ! empty( $param['link'][ $i ] ) ? $param['link'][ $i ] : '#';
				$interaction = 'function:' . esc_attr( $link );
				$interaction .= $this->add_tracking( $i );
				$out         .= 'href="#" data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				break;
			case 'event':
				$link        = ! empty( $param['link'][ $i ] ) ? $param['link'][ $i ] : '#';
				$interaction = 'targetEvent:' . esc_attr( $link );
				$interaction .= $this->add_tracking( $i );
				$out         .= 'href="#" data-flexi-interaction="' . esc_attr( $interaction ) . '"';
				break;
			//endregion
		}

		return ' ' . $out;
	}


	private function add_tracking( $i ): string {
		$param = $this->param['item'];
		$out   = '';
		if ( empty( $param['enable_tracking'][ $i ] ) ) {
			return $out;
		}

		$out .= ' track:{';

		if ( ! empty( $param['google_event'][ $i ] ) ) {
			$out .= ' event:' . $param['google_event'][ $i ];
		}

		if ( ! empty( $param['google_category'][ $i ] ) ) {
			$out .= ' category:' . $param['google_category'][ $i ];
		}

		if ( ! empty( $param['google_action'][ $i ] ) ) {
			$out .= ' action:' . $param['google_action'][ $i ];
		}

		if ( ! empty( $param['google_label'][ $i ] ) ) {
			$out .= ' label:' . $param['google_label'][ $i ];
		}

		if ( ! empty( $param['google_value'][ $i ] ) ) {
			$out .= ' value:' . $param['google_value'][ $i ];
		}

		$out .= '}';

		return $out;
	}

	private function _get_current_url(): ?string {
		global $wp;

		return home_url( add_query_arg( [], $wp->request ) );
	}

	private function create_icon( $i ): string {
		$param       = $this->param['item'];
		$icon_type   = ! empty( $param['icon_type'][ $i ] ) ? $param['icon_type'][ $i ] : 'icon';
		$icon_rotate = ! empty( $param['icon_rotate'][ $i ] ) ? $param['icon_rotate'][ $i ] : 0;
		$icon_flip   = ! empty( $param['icon_flip'][ $i ] ) ? $param['icon_flip'][ $i ] : '';


		$class = '';
		$style = '';
		if ( ! empty( $icon_flip ) ) {
			$class .= ' ' . $icon_flip;
		}

		if ( ! empty( $icon_rotate ) ) {
			$style .= '--flexi-icon_rotate:' . $icon_rotate . ';';
		}

		$out = '<span class="fleximenu-icon">';

		$style = ! empty( $style ) ? ' style="' . esc_attr( $style ) . '"' : '';

		if ( $icon_type === 'icon' ) {
			$icon = $param['icon'][ $i ];
			$out  .= '<span class="' . esc_attr( $icon ) . esc_attr( $class ) . '"' . wp_kses_post( $style ) . '></span>';
		} elseif ( $icon_type === 'image' ) {
			$img_link = $param['image'][ $i ];
			$img_alt  = $param['image_alt'][ $i ];
			$out      .= '<img';
			$out      .= ! empty( $class ) ? ' class="' . esc_attr( $class ) . '"' : '';
			$out      .= wp_kses_post( $style );
			$out      .= ' src="' . esc_url( $img_link ) . '" alt="' . esc_attr( $img_alt ) . '">';
		} elseif ( $icon_type === 'class' ) {
			$icon = $param['icon_class'][ $i ] || '';
			$out  .= '<span class="' . esc_attr( $icon ) . esc_attr( $class ) . '"' . wp_kses_post( $style ) . '></span>';
		} elseif ( $icon_type === 'emoji' ) {
			$icon = ! empty( $param['emoji'][ $i ] ) ? $param['emoji'][ $i ] : '';
			$out  .= '<span';
			$out  .= ! empty( $class ) ? ' class="' . esc_attr( $class ) . '"' : '';
			$out  .= wp_kses_post( $style );
			$out  .= '>';
			$out  .= wp_kses_post( $icon );
			$out  .= '</span>';
		}
		$out .= '</span>';

		return $out;
	}

	private function create_label( $i ): string {
		$param = $this->param['item'];
		$out   = '<span class="fleximenu-label">';
		$out   .= ! empty( $param['label'][ $i ] ) ? esc_html( $param['label'][ $i ] ) : '';
		$out   .= '</span>';

		return $out;
	}

	private function create_dialog( $count ): string {
		$param = $this->param['item'];
		$out   = '';

		for ( $i = 0; $i < $count; $i ++ ) {
			if ( $param['type'][ $i ] !== 'dialog' ) {
				continue;
			}
			$class       = ! empty( $this->param['dialog_shadow'] ) ? ' -shadow' : '';
			$dialogId    = 'flexiMenuDialog_' . $this->id . '_' . $i;
			$interaction = 'dialog:' . $dialogId . ' close';
			$out         .= '<dialog id="' . esc_attr( $dialogId ) . '" class="fleximenu-dialog' . esc_attr( $class ) . '"';
			$out         .= $this->dialog_style();
			$out         .= '>';
			$out         .= '<div class="fleximenu-dialog-content">';
			$out         .= do_shortcode( wp_kses_post( wpautop( $param['text'][ $i ] ) ) );
			$out         .= '</div>';
			$out         .= '<button aria-label="' . esc_attr__( 'Close Dialog', 'flexi-menu' ) . '" class="fleximenu-dialog-close" type="button" data-flexi-interaction="' . esc_attr( $interaction ) . '"></button>';
			$out         .= '</dialog>';
		}

		return $out;
	}

	private function dialog_style(): string {
		$out = '';

		$args = [
			'dialog_border_width' => '0',
			'dialog_max_width'    => '550',
			'dialog_max_height'   => '450',
			'dialog_radius'       => '4',
			'dialog_border_color' => '#383838',
			'dialog_backdrop'     => 'rgba(0, 0, 0, 0.2)',
			'dialog_close'        => '#000000',
		];

		foreach ( $args as $key => $default ) {
			$out .= $this->get_param( $key, $default );
		}

		if ( ! empty( $out ) ) {
			$out = ' style="' . esc_attr( $out ) . '"';
		}

		return $out;
	}

}