<?php

namespace Fab\Model;

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

use Fab\Helper\FABItem;
use Fab\Interfaces\Model_Interface;

/**
 * FAB Model.
 *
 * @package    Fab
 * @subpackage Fab/Model
 */
class Fab extends Model implements Model_Interface {

    /**
     * WordPress global $post variable.
     *
     * @var array
     */
    protected $post;

    /**
     * Fabs.
     *
     * @var array
     */
    protected $fabs = array();

    /**
     * Constructor.
     */
    public function __construct() {
        parent::__construct();

        // Set post type args.
        $this->args['public']             = true;
        $this->args['publicly_queryable'] = false; // @deprecated : true before used for Elementor, this is set to false to avoid public access to the FAB post type.
        $this->args['menu_icon']          = json_decode( FAB_PATH )->plugin_url . '/assets/img/icon.png';
        $this->args['has_archive']        = false;
        $this->args['show_in_rest']       = true;
        $this->args['supports']           = array( 'title', 'editor', 'thumbnail' );
    }

    /**
     * Register save post action for current post type.
     *
     * @param int     $post_id The post ID.
     * @param WP_Post $post The post object.
     * @param bool    $update Whether the post is being updated.
     * @return void
     */
    public function register_save_post_action( $post_id, $post, $update ) {
        global $post;

        // Check Correct Post Type, Ignore Trash.
        if ( ! isset( $post->ID ) || 'fab' !== $post->post_type ) {
            return;
        }

        // Save FAB.
        do_action( 'fab_save_post', $post_id, $post, $update );
    }

    /**
     * Load fabs from database.
     *
     * @return void
     */
    public function load_fabs() {
        // Grab Data - Ordered Data.
        $fab_order = \FAB()->getConfig()->options->fab_order ?? array();
        $items     = array_map( 'get_post', $fab_order );
        $order     = array_flip( $fab_order );

        // Set post status.
        $post_status = array( 'publish' );
        if ( \FAB()->Helper->is_preview_page() ) {
            $post_status[] = 'draft';
        }

        // Grab Data - Unordered.
        $items = array_merge(
            $items,
            get_posts(
                array(
                    'posts_per_page' => -1,
                    'post_type'      => $this->name,
                    'post_status'    => $post_status,
                    'post__not_in'   => empty( $fab_order ) ?
                        array( 'empty' ) : $fab_order,
                    'orderby'        => 'post_date',
                    'order'          => 'DESC',
                )
            )
        );

        // Filter fabs.
        $filtered_items = array();
        foreach ( $items as $item ) {
            // Check if item exists.
            if ( ! isset( $item->ID ) ) {
                continue;
            }

            // Check if status is valid.
            if ( ! in_array( $item->post_status, $post_status, true ) ) {
                continue;
            }

            $filtered_items[] = $item;
        }
        $items = $filtered_items;

        $this->fabs = compact( 'order', 'items' );
    }

    /**
     * Return fabs item and fabs order
     *
     * Args :
     * - validateLocation : check if function should validate location rules.
     * - filterbyType : check if function should filter by type.
     * - filtercustommodule : check if function should filter custom module.
     *
     * @param array $args   Arguments.
     * @return array
     */
    public function get_lists_of_fab( $args = array() ) {
        global $post;

        // Data.
        $order  = array();
        $items  = array();
        $custom = array(
            'readingbar'  => false,
            'scrolltotop' => false,
        );

        // Set default args.
        $args['validateLocation'] = isset( $args['validateLocation'] ) ? $args['validateLocation'] : true;
        $args['validateLocation'] = \FAB()->Helper->is_preview_page() ? false : $args['validateLocation'];

        // Load fabs if empty.
        if ( empty( $this->fabs ) ) {
            $this->load_fabs();
        }

        // Get data from fabs.
        $order = $this->fabs['order'];
        $items = $this->fabs['items'];

        // Filter by Location.
        $tmp = array();
        foreach ( $items as &$item ) {
            // We place it here due to location rules requires global $post variable.
            // Some hooks doesn't have it, ex. widgets_init.
            $item = new FABItem( $item->ID );

            // Check builder.
            if ( isset( $args['builder'] ) && ! in_array( $item->getBuilder(), $args['builder'], true ) ) {
                continue;
            }

            // FAB Item Grab Custom Module.
            if ( in_array( $item->getType(), array_keys( $custom ), true ) ) {
                $custom[ $item->getType() ] = $item;
                if ( isset( $args['filtercustommodule'] ) ) {
                    continue;
                }
            }

            // Check location rules.
            if ( $args['validateLocation'] &&
                ! empty( $item->getLocations() ) &&
                ! $item->isToBeDisplayed()
            ) {
                continue;
            }

            // Check third party location rules.
            // There are some third party plugins that handle the location rules, by filters.
            if (
                $args['validateLocation'] &&
                ! $item->isToBeDisplayed()
            ) {
                continue;
            }

            // Filter by type.
            if ( isset( $args['filterbyType'] ) && ! in_array( $item->getType(), $args['filterbyType'], true ) ) {
                continue;
            }

            // Order FAB Item.
            if ( ! isset( $order[ $item->getID() ] ) ) {
                $order[ $item->getID() ] = count( $order );
            }

            // Grab Location.
            $tmp[] = $item;
        }
        unset( $item );
        $items = $tmp;

        return array(
            'order'  => array_flip( $order ),
            'items'  => $items,
            'custom' => $custom,
        );
    }

    /**
     * Register post type.
     */
    public function register_post_type() {
        // Set labels: We defined it here because __() function is only available under init hook.
        $this->args['labels'] = array(
            'name'                  => strtoupper( $this->name ),
            // translators: %s: Post type singular name (uppercase).
            'add_new_item'          => sprintf( __( 'Add New %s', 'floating-awesome-button' ), strtoupper( $this->name ) ),
            // translators: %s: Post type singular name (uppercase).
            'edit_item'             => sprintf( __( 'Edit %s', 'floating-awesome-button' ), strtoupper( $this->name ) ),
            // translators: %s: Post type singular name (uppercase).
            'new_item'              => sprintf( __( 'New %s', 'floating-awesome-button' ), strtoupper( $this->name ) ),
            // translators: %s: Post type singular name (uppercase).
            'view_item'             => sprintf( __( 'View %s', 'floating-awesome-button' ), strtoupper( $this->name ) ),
            // translators: %s: Post type plural name (uppercase).
            'view_items'            => sprintf( __( 'View %s', 'floating-awesome-button' ), strtoupper( $this->name ) ),
            // translators: %s: Post type plural name (uppercase).
            'search_items'          => sprintf( __( 'Search %s', 'floating-awesome-button' ), strtoupper( $this->name ) ),
            // translators: %s: Post type plural name (lowercase).
            'not_found'             => sprintf( __( 'No %s found', 'floating-awesome-button' ), strtolower( $this->name ) ),
            // translators: %s: Post type plural name (lowercase).
            'not_found_in_trash'    => sprintf( __( 'No %s found in Trash', 'floating-awesome-button' ), strtolower( $this->name ) ),
            // translators: %s: Post type plural name (uppercase).
            'all_items'             => sprintf( __( 'All %s', 'floating-awesome-button' ), strtoupper( $this->name ) ),
            // translators: %s: Post type plural name (uppercase).
            'archives'              => sprintf( __( '%s Archives', 'floating-awesome-button' ), strtoupper( $this->name ) ),
            // translators: %s: Post type singular name (lowercase).
            'insert_into_item'      => sprintf( __( 'Insert into %s', 'floating-awesome-button' ), strtolower( $this->name ) ),
            // translators: %s: Post type singular name (lowercase).
            'uploaded_to_this_item' => sprintf( __( 'Uploaded to this %s', 'floating-awesome-button' ), strtolower( $this->name ) ),
        );

        // Register post type.
        register_post_type( $this->name, $this->args );
    }

    /*
    |--------------------------------------------------------------------------
    | Fulfill implemented interface contracts
    |--------------------------------------------------------------------------
     */

    /**
     * Execute Class.
     *
     * @return void
     */
    public function run() {
        // Register save post action for current post type.
        add_action( 'save_post', array( $this, 'register_save_post_action' ), 10, 3 );

        // Register post type.
        add_action( 'init', array( $this, 'register_post_type' ) );
    }
}
