<?php

namespace Fab\Helper;

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

use Fab\Metabox\FABMetaboxLocation;
use Fab\Metabox\FABMetaboxSetting;
use Fab\Metabox\FABMetaboxDesign;
use Fab\Metabox\FABMetaboxTrigger;
use Fab\Module\FABModuleAuthLogin;
use Fab\Module\FABModuleAuthLogout;
use Fab\Module\FABModuleReadingBar;
use Fab\Module\FABModuleScrollToTop;
use Fab\Module\FABModuleAnchorLink;
use Fab\Module\FABModuleSearch;
use Fab\View;

/**
 * FAB Item.
 *
 * @package    Fab
 * @subpackage Fab/Helper
 */
class FABItem {

    // Load trait.
    use GetterSetter;

    /**
     * ID
     *
     * @access   protected
     * @var      int    $ID    ID
     */
    protected $ID;

    /**
     * Post
     * - This will be used for single post type.
     *
     * @access   protected
     * @var      object    $post    Post
     */
    protected $post;

    /**
     * Title
     *
     * @access   protected
     * @var      string    $title    Title
     */
    protected $title;

    /**
     * No HTML Content
     * - Content without HTML tags.
     *
     * @access   protected
     * @var      string    $no_html_content Content without HTML tags
     */
    protected $no_html_content;

    /**
     * Raw Content
     * - Content with HTML tags.
     *
     * @access   protected
     * @var      string    $raw_content Content with HTML tags
     */
    protected $raw_content;

    /**
     * Slug
     *
     * @access   protected
     * @var      string    $slug    slug
     */
    protected $slug;

    /**
     * Status
     *
     * @access   protected
     * @var      string    $status    status
     */
    protected $status;

    /**
     * Icon Class
     *
     * @access   protected
     * @var      array    $icon_class    icon_class
     */
    protected $icon_class;

    /**
     * Responsive
     *
     * @access   protected
     * @var      array    $responsive    responsive
     */
    protected $responsive = array();

    /**
     * Size
     *
     * @access   protected
     * @var      array    $size    design
     */
    protected $size = array();

    /**
     * Should the button be standalone or not.
     *
     * @access   protected
     * @var      string    $standalone    standalone
     */
    protected $standalone;

    /**
     * Type
     *
     * @access   protected
     * @var      string    $type    type
     */
    protected $type;

    /**
     * Link
     *
     * @access   protected
     * @var      string    $link    link
     */
    protected $link = '';

    /**
     * Link Behavior
     *
     * @access   protected
     * @var      string    $linkBehavior    linkBehavior
     */
    protected $linkBehavior = false;

    /**
     * Link Href : Controls if item can use href attribute
     *
     * @access   protected
     * @var      string    $linkHref    linkHref
     */
    protected $linkHref = false;

    /**
     * Hotkey
     *
     * @access   protected
     * @var      string    $hotkey    hotkey
     */
    protected $hotkey;

    /**
     * Animation
     *
     * @access   protected
     * @var      array    $animation    animation
     */
    protected $animation = array();

    /**
     * Check if item is a button and should be displayed as a button
     *
     * @access   protected
     * @var      bool    $isButton    isButton
     */
    protected $isButton = true;

    /**
     * Modal
     *
     * @access   protected
     * @var      FABModal|null    $modal    modal
     */
    protected $modal = null;

    /**
     * Module
     *
     * @access   protected
     * @var      FABModule    $module    module
     */
    protected $module;

    /**
     * Trigger
     *
     * @access   protected
     * @var      array    $trigger    trigger
     */
    protected $trigger = array();

    /**
     * Template
     *
     * @access   protected
     * @var      array    $template    template
     */
    protected $template = array();

    /**
     * Tooltip
     *
     * @access   protected
     * @var      array    $tooltip    tooltip
     */
    protected $tooltip = array();

    /**
     * Tooltip Display
     *
     * @access   protected
     * @var      array    $tooltipDisplay    Tooltip Display
     */
    protected $tooltipDisplay;

    /**
     * Countdown Timer Display
     *
     * @access   protected
     * @var      bool    $countdownTimerDisplay    Countdown Timer Display
     */
    protected $countdownTimerDisplay;

    /**
     * Locations
     *
     * @access   protected
     * @var      array|string    $locations    locations setting
     */
    protected $locations;

    /**
     * To Be Displayed
     *
     * @access   protected
     * @var      bool    $to_be_displayed    to be displayed or not
     */
    protected $to_be_displayed;

    /**
     * Location Is Valid
     * - We require this attribute because there's racing condition between fab_item_data and woocommerce_cart_updated.
     * - Which by relaying only using to_be_displayed, we can't determine if the location rules is valid or not.
     *
     * @access   protected
     * @var      bool    $location_is_valid    location is valid or not
     */
    protected $location_is_valid;

    /**
     * Builder
     *
     * @access   protected
     * @var      string    $builder    builder (classic, guttenberg, elementor, beaver builder, etc)
     */
    protected $builder;

    /**
     * Extra Options
     * - Print Target : CSS selector of element to print. Default is body.
     * - Scroll Duration : Window scroll duration in miliseconds.
     *
     * @access   protected
     * @var      array    $extraOptions    extra options
     */
    protected $extraOptions = array();

    /**
     * Toast
     *
     * @access   protected
     * @var      array    $toast    toast
     */
    protected $toast = array();

    /**
     * Third Party Integration Data
     * - This will be used to store additional data for the FAB item.
     * - This is used for third party integrations such as WooCommerce, etc.
     *
     * @access protected
     * @var array $third_party_data
     */
    protected $third_party_data = array();

    /**
     * Format fab item to send to view.
     *
     * @param int $ID FAB Item ID.
     * @return void
     */
    public function __construct( int $ID ) {
        // Construct Class.
        $this->ID                = $ID;
        $this->to_be_displayed   = true;
        $this->location_is_valid = true;
        $this->title             = $this->do_placeholder( get_post_field( 'post_title', $this->ID ) );
        $this->slug              = get_post_field( 'post_name', $this->ID );
        $this->status            = get_post_field( 'post_status', $this->ID );
        $this->icon_class        = get_post_meta( $this->ID, FABMetaboxDesign::$post_metas['icon_class']['meta_key'], true );
        $this->type              = get_post_meta( $this->ID, FABMetaboxSetting::$post_metas['type']['meta_key'], true );

        // Load Function.
        $this->load_content();

        // Construct Function.
        $this->construct_grab_module();
        $this->load_and_transform_attributes();

        // Extra Function.
        $this->detect_builder(); // Detect content builder.
    }

    /**
     * Load content from database.
     *
     * @return void
     */
    public function load_content() {
        global $wp_embed;

        // Load content from database.
        $content = get_post_field( 'post_content', $this->ID );

        // Transform content.
        // We don't support shortcode in FAB item content, because it handled by popup.
        // We don't see any use case for shortcode in FAB item content yet, maybe later in the future.
        $content = $this->do_placeholder( $content ); // Implement fab custom {...} placeholders.
        $content = $wp_embed->autoembed( do_blocks( $content ) );

        // Assign content to properties.
        // - Content is used for toast or button content, which does not require HTML tags.
        // - Raw content is used for popup content, which require HTML tags.
        $this->raw_content     = wp_kses_post( $content );
        $this->no_html_content = str_replace( array( "\n", "\r" ), '', wp_strip_all_tags( wp_kses_post( $content ) ) );
    }

    /**
     * Implement fab custom {...} shortcode.
     *
     * @param string $text Text to replace placeholders in.
     * @param array  $data Additional placeholder data.
     * @return string
     */
    public function do_placeholder( $text, $data = array() ) {
        global $wp, $post;

        // Add placeholder filters.
        $placeholders = apply_filters( 'fab_placeholders', array() );

        // Merge user-provided data with placeholders (user values take priority).
        $replacements = array_merge( $placeholders, $data );

        // Create search/replace arrays.
        $search  = array_keys( $replacements );
        $replace = array_values( $replacements );

        // Perform the replacement.
        return str_replace( $search, $replace, $text );
    }

    /**
     * Grab Module
     *
     * @deprecated 1.0.0 - this will soon be removed.
     *
     * @return void
     */
    public function construct_grab_module() {
        $modules = array(
            FABModuleAuthLogin::class,
            FABModuleAuthLogout::class,
            FABModuleScrollToTop::class,
            FABModuleSearch::class,
        );
        foreach ( $modules as $moduleClass ) {
            if ( $moduleClass::$type === $this->type ) {
                $this->module = new $moduleClass();
                break;
            }
        }
    }

    /**
     * Load and transform attributes
     *
     * @return void
     */
    public function load_and_transform_attributes() {
        // Hotkey.
        $this->hotkey = get_post_meta( $this->ID, FABMetaboxDesign::$post_metas['hotkey']['meta_key'], true );
        $this->hotkey = ( 'none' === $this->hotkey ) ? '' : $this->hotkey;

        // Size.
        $this->size = array(
            'type'   => ( get_post_meta( $this->ID, FABMetaboxDesign::$post_metas['size_type']['meta_key'], true ) ) ?
                get_post_meta( $this->ID, FABMetaboxDesign::$post_metas['size_type']['meta_key'], true ) : 'medium',
            'custom' => ( get_post_meta( $this->ID, FABMetaboxDesign::$post_metas['size_custom']['meta_key'], true ) ) ?
                get_post_meta( $this->ID, FABMetaboxDesign::$post_metas['size_custom']['meta_key'], true ) : '',
        );

        // Animation.
        $default         = FABMetaboxDesign::$input['fab_design_animation']['default'];
        $this->animation = get_post_meta( $this->ID, FABMetaboxDesign::$post_metas['animation']['meta_key'], true );
        $this->animation = ( $this->animation ) ? \FAB()->Helper->ArrayMergeRecursive( (array) $default, (array) $this->animation ) : $default;

        // Responsive.
        $default          = FABMetaboxDesign::$input['fab_design_responsive']['default'];
        $this->responsive = get_post_meta( $this->ID, FABMetaboxDesign::$post_metas['responsive']['meta_key'], true );
        $this->responsive = ( $this->responsive ) ? \FAB()->Helper->ArrayMergeRecursive( (array) $default, (array) $this->responsive ) : $default;

        // Standalone.
        $this->standalone = ( ! $this->standalone ) ? get_post_meta( $this->ID, FABMetaboxDesign::$post_metas['standalone']['meta_key'], true ) : $this->standalone;
        $this->standalone = \FAB()->Helper->transform_yes_no_value( $this->standalone );

        // Trigger.
        $default       = FABMetaboxTrigger::$input['fab_trigger']['default'];
        $this->trigger = get_post_meta( $this->ID, FABMetaboxTrigger::$post_metas['trigger']['meta_key'], true );
        $this->trigger = ( $this->trigger ) ? \FAB()->Helper->ArrayMergeRecursive( (array) $default, (array) $this->trigger ) : $default;

        // Template.
        $default        = FABMetaboxDesign::$input['fab_design_template']['default'];
        $this->template = get_post_meta( $this->ID, FABMetaboxDesign::$post_metas['template']['meta_key'], true );
        $this->template = ( $this->template ) ? \FAB()->Helper->ArrayMergeRecursive( (array) $default, (array) $this->template ) : $default;

        // Tooltip.
        $default              = FABMetaboxDesign::$input['fab_design_tooltip']['default'];
        $this->tooltip        = get_post_meta( $this->ID, FABMetaboxDesign::$post_metas['tooltip']['meta_key'], true );
        $this->tooltip        = ( $this->tooltip ) ? \FAB()->Helper->ArrayMergeRecursive( (array) $default, (array) $this->tooltip ) : $default;
        $this->tooltipDisplay = \FAB()->Helper->transformBooleanValue( $this->tooltip['alwaysdisplay'] ) !== 0 ? true : false;

        // Force displaying tooltip if no icon is set.
        if ( ! $this->icon_class ) {
            $this->tooltipDisplay           = true;
            $this->tooltip['alwaysdisplay'] = true;
        }

        // Countdown Timer.
        $this->countdownTimerDisplay = \FAB()->Helper->transformBooleanValue( $this->tooltip['countdown_timer'] ) !== 0 ? true : false;

        // Location.
        $this->locations = get_post_meta( $this->ID, FABMetaboxLocation::$post_metas['locations']['meta_key'], true );
        $this->locations = ( $this->locations ) ? json_decode( $this->locations, true ) : array();
        $this->locations = \FAB()->Helper->transformLocationValue( $this->locations );

        // HOOK: Add action to allow modification when loading and transforming attributes.
        do_action( 'fab_item_data', $this );
    }

    /**
     * Detect content builder
     *
     * @return void
     */
    public function detect_builder() {
        if ( is_plugin_active( 'elementor/elementor.php' ) && \Elementor\Plugin::instance()->documents->get( $this->getID() )->is_built_with_elementor() ) {
            // Elementor builder.
            $this->builder = 'elementor';
        } else { // Default builder.
            $this->builder = 'default';
        }
    }

    /**
     * Render FAB by type
     *
     * @return void
     */
    public function render() {
        if ( $this->module && method_exists( $this->module, 'render' ) ) {
            $this->module->render();
        }

        // HOOK: Add action to allow modification when rendering the FAB item.
        do_action( 'fab_item_render', $this );
    }

    /**
     * Render FAB Content
     *
     * @param string $content Content to render.
     * @return void
     */
    public function render_content( $content = '' ) {
        // Get layout.
        $layout = isset( $this->getModal()->getLayout()['id'] ) ?
            $this->getModal()->getLayout()['id'] : 'stacked';

        // Render content.
        View::RenderStatic(
            sprintf( 'Template/modal/layout/%s', $layout ),
            array(
                'fab_item' => $this,
                'content'  => ( 'elementor' === $this->builder ) ? $content : $this->getRawContent(),
            )
        );
    }

    /**
     * Render FAB Widget
     */
    public function render_widget() {
        dynamic_sidebar( sprintf( 'fab-widget-%s', $this->getSlug() ) );
    }

    /**
     * @return int
     */
    public function getID(): int {
        return $this->ID;
    }

    /**
     * @param int $ID
     */
    public function setID( int $ID ): void {
        $this->ID = $ID;
    }

    /**
     * @return string
     */
    public function getTitle() {
        return $this->title;
    }

    /**
     * @param string $title
     */
    public function setTitle( $title ): void {
        $this->title = $title;
    }

    /**
     * @return string
     */
    public function getContent() {
        return $this->no_html_content;
    }

    /**
     * @param string $content
     */
    public function setContent( $content ): void {
        $this->no_html_content = $content;
    }

    /**
     * @return string
     */
    public function getRawContent() {
        return $this->raw_content;
    }

    /**
     * @param string $raw_content
     */
    public function setRawContent( $raw_content ): void {
        $this->raw_content = $raw_content;
    }

    /**
     * @return array
     */
    public function getSlug() {
        return $this->slug;
    }

    /**
     * @param array $slug
     */
    public function setSlug( $slug ): void {
        $this->slug = $slug;
    }

    /**
     * @return array
     */
    public function getIconClass() {
        /** TODO: OLDCODE must be removed next major version */
        $oldData = get_post_meta( $this->ID, 'fab_setting_icon_class', true );
        if ( $oldData ) {
            update_post_meta( $this->ID, FABMetaboxDesign::$post_metas['icon_class']['meta_key'], $oldData );
        }
        /** TODO: OLDCODE must be removed next major version */

        return ( $this->icon_class ) ? $this->icon_class : 'fas fa-circle';
    }

    /**
     * @param array $icon_class
     */
    public function setIconClass( $icon_class ): void {
        $this->icon_class = $icon_class;
    }

    /**
     * @return array
     */
    public function getSize(): array {
        return $this->size;
    }

    /**
     * @param array $size
     */
    public function setSize( array $size ): void {
        $this->size = $size;
    }

    /**
     * @return string
     */
    public function getType() {
        return $this->type;
    }

    /**
     * @param string $type
     */
    public function setType( $type ): void {
        $this->type = $type;
    }

    /**
     * @return array
     */
    public function getAnimation() {
        return $this->animation;
    }

    /**
     * @param array $animation
     */
    public function setAnimation( $animation ): void {
        $this->animation = $animation;
    }

    /**
     * @return FABModal|null
     */
    public function getModal() {
        return $this->modal;
    }

    /**
     * @param FABModal $modal
     */
    public function setModal( FABModal $modal ): void {
        $this->modal = $modal;
    }

    /**
     * @return bool
     */
    public function isToBeDisplayed(): bool {
        return $this->to_be_displayed;
    }

    /**
     * @param bool $to_be_displayed
     */
    public function setToBeDisplayed( bool $to_be_displayed ): void {
        $this->to_be_displayed = $to_be_displayed;
    }

    /**
     * @return bool
     */
    public function isCountdownTimerDisplayed(): bool {
        return $this->countdownTimerDisplay;
    }

    /**
     * @return string
     */
    public function getBuilder(): string {
        return $this->builder;
    }

    /**
     * @param string $builder
     */
    public function setBuilder( string $builder ): void {
        $this->builder = $builder;
    }

    /**
     * @return array
     */
    public function getExtraOptions(): array {
        return $this->extraOptions;
    }

    /**
     * @param array $extraOptions
     */
    public function setExtraOptions( array $extraOptions ): void {
        $this->extraOptions = array_merge( $this->extraOptions, $extraOptions );
    }

    /** Grab All Assigned Variables */
    public function getVars() {
        $data = get_object_vars( $this );

        // Get the modal variables.
        if ( $this->modal ) {
            $data['modal'] = $this->modal->getVars();
        }

        // Get the module variables.
        if ( $this->module ) {
            $data['module'] = $this->module->getVars();
        }

        // Remove unnecessary objects.
        unset( $data['Helper'] );
        unset( $data['WP'] );

        return $data;
    }

    /**
     * Grab All Toasts
     *
     * @return array
     */
    public function getToast(): array {
        return $this->toast;
    }

    /**
     * Set Toast Configuration (Partial Update)
     *
     * @param array $toast
     * @return void
     */
    public function setToast( array $toast ): void {
        $this->toast = array_merge( $this->toast, $toast );
    }
}
