<?php

namespace Reach\App\Modules;

use Reach\App\Attachments\Media;
use Reach\App\Fields\AlbumOptions;
use Reach\App\Interfaces\WordPressHooks;
use Reach\App\Theme\ThemeStyles;
use Reach\App\Core\Transients;
use Reach\App\Fields\SiteOptions;
use Reach\App\Fields\Util;

/**
 * Class Modules
 *
 * @package Reach\App\Modules
 */
class Modules implements WordPressHooks {

    /**
     * Front page option ID
     */
    public $front_page_id;

    /**
     * Modules constructor.
     */
    public function __construct() {
        $this->front_page_id = get_option( 'page_on_front' );
    }

    /**
     * Add class hooks.
     */
    public function addHooks() {
        add_filter( 'reach/modules/classes/text', [ $this, 'outputModuleTextClasses' ], 10, 2 );
        add_action( 'reach/modules/video', [ $this, 'outputModuleVideoElement' ] );
        add_action( 'reach/modules/parallax', [ $this, 'outputModuleParallaxElement' ] );
        add_action( 'reach/modules/output', [ $this, 'outputPageModules' ] );
        add_action( 'reach/modules/footer', [ $this, 'outputBackToTop' ] );
        add_action( 'reach/modules/refresh', [ $this, 'updatePageModuleMeta' ] );
        add_action( 'reach/before_module_content', [ $this, 'openModuleContainer' ] );
        add_action( 'reach/after_module_content', [ $this, 'closeModuleContainer' ] );
    }

    /**
     * Check the current page for available modules and include them in the template
     *
     * @param $post_id
     */
    public function outputPageModules( $post_id ) {
        $page_modules      = get_option( 'options_page_modules_' . $post_id );
        $exclude_for_cache = apply_filters( 'reach/modules/transients/exclude', [
            'form'
        ] );

        if ( 'albums' === get_post_type( $post_id ) ) {
            $album        = ( new AlbumOptions() );
            $page_modules = [
                'gallery-' . $album->group_key
            ];
        }

        if ( $page_modules && is_array( $page_modules ) ) {
            // get page meta to pass into module templates
            $page_meta    = get_post_meta( $post_id );
            $front_page   = get_option( 'page_on_front' );
            $design_style = ( new ThemeStyles() )->getThemeDesignStyle();
            $module_class = 'module' . ( get_the_ID() === (int) $this->front_page_id ? '--home' : '--interior' );

            // loop through active page modules and include each template
            foreach ( $page_modules as $index => $module ) {
                // remove the group key from the module name so we can call the proper template file
                $filtered_module = strstr( $module, '-group', true );
                $group_key       = strstr( $module, 'group' );

                // check that the file for this module exists
                $file = locate_template( 'modules/' . $filtered_module . '.php' );
                if ( $file ) {
                    // check if the module we're grabbing should be excluded from our transient cache
                    if ( ( defined( 'REACH_TRANSIENTS' ) && (bool) REACH_TRANSIENTS ) && ! in_array( $filtered_module, $exclude_for_cache ) ) {
                        $transient_key = 'page_' . $post_id . '_section_' . $module;
                        // check for existing transient data
                        $output = get_transient( $transient_key ) ?: false;

                        // If we got our transient data, output that and skip this the rest of the loop iteration
                        if ( $output ) {
                            echo $output;
                            continue;
                        }

                        // Turn on output buffering
                        ob_start();

                        // include the module file
                        include( $file );

                        // Return the contents of the output buffer
                        $output = ob_get_contents();
                        ob_end_clean();

                        // cache our returned output in a transient to reduce page queries
                        ( new Transients() )->registerTransients( $transient_key );
                        set_transient( $transient_key, $output );

                        echo $output;
                    } else {
                        // include the module file
                        include( $file );
                    }
                }
            }
        }
    }

    /**
     * Output the text class for the module
     */
    public function outputModuleTextClasses( $default, $text_color ) {

        return ' text--' . ThemeStyles::colorLightOrDark( $text_color, 'light', 'dark' );
    }

    /**
     * Output the back to top link in the footer module on mobile views
     */
    public function outputBackToTop() {
        // get site options
        $options = SiteOptions::getSiteOptions();

        // check that the back to top link is enabled
        if ( empty( $options['back_to_top'] ) || ! $options['back_to_top'] ) {
            return;
        }

        echo '<div class="footer__scroll-top"><a id="scrollTop" href="javascript:;"><svg class="icon icon-chevron-up"><use xlink:href="#icon-chevron-up"></use></svg>' . __( 'Back to the top', 'reach' ) . '</a></div>';
    }

    /**
     * Output the bootstrap grid container divs if our current module isn't excluded
     *
     * @param $module_slug
     */
    public function openModuleContainer( $module_slug ) {
        $excluded = apply_filters( 'reach/modules/container', [
            'gallery',
            'image',
            'table',
            'content-blocks'
        ] );
        // check if our current module slug is to be excluded from this markup
        if ( in_array( $module_slug, $excluded ) ) {
            return;
        }

        echo '<div class="container">';
        echo '<div class="row">';
    }

    /**
     * Output the closing bootstrap grid container divs if our current module isn't excluded
     *
     * @param $module_slug
     */
    public function closeModuleContainer( $module_slug ) {
        $excluded = apply_filters( 'reach/modules/container', [
            'gallery',
            'image',
            'table',
            'content-blocks'
        ] );
        // check if our current module slug is to be excluded from this markup
        if ( in_array( $module_slug, $excluded ) ) {
            return;
        }

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

    /**
     * Output video element within a module if the background size IS NOT set as parallax.
     *
     * @param $background
     *
     * @return string
     */
    public function outputModuleVideoElement( $background ) {
        if ( empty( $background['image'] ) || empty( $background['video_mp4'] ) || ( ! empty( $background['size'] ) && 'parallax' === $background['size'] ) ) {
            return '';
        }

        // get background image and video URL
        $background_image     = Media::getAttachmentByID( $background['image'] );
        $background_video_mp4 = Media::getAttachmentByID( $background['video_mp4'] );

        printf(
            '<video playsinline autoplay muted loop aria-label="%1$s" poster="%2$s" class="background__video">
                <source src="%3$s" type="video/mp4">
            </video>',
            $background_video_mp4->title,
            $background_image->sizes['featured-large'],
            ( ! empty( $background_video_mp4->url ) ? esc_url( $background_video_mp4->url ) : '' )
        );
    }

    /**
     * Output video element within a module if the background size IS set as parallax.
     *
     * @param $background
     *
     * @return string
     */
    public function outputModuleParallaxElement( $background ) {
        if ( empty( $background['image'] ) || ( ! empty( $background['size'] ) && 'parallax' !== $background['size'] && 'parallax_all' !== $background['size'] ) ) {
            return '';
        }

        // get background image URL
        $background_mobile     = $background_video = '';
        $background_image      = Media::getAttachmentByID( $background['image'] );
        $background_video_mp4  = ! empty( $background['video_mp4'] ) ? Media::getAttachmentByID( $background['video_mp4'] ) : false;
        $background_video_webm = ! empty( $background['video_webm'] ) ? Media::getAttachmentByID( $background['video_webm'] ) : false;

        if ( ! empty( $background['mobile_image'] ) ) {
            $background_mobile = Media::getAttachmentByID( $background['mobile_image'] );
        }

        if ( ! empty( $background_video_mp4 ) || ! empty( $background_video_webm ) ) {
            $background_video = 'data-jarallax-video="';
            $background_video .= ! empty( $background_video_mp4 ) ? 'mp4:' . esc_url( $background_video_mp4->url ) . ',' : '';
            $background_video .= ! empty( $background_video_webm ) ? 'webm:' . esc_url( $background_video_webm->url ) : '';
            $background_video .= '"';
        }

        printf(
            '<div class="jarallax" %2$s>
               <img class="jarallax-img" data-src="%1$s" %3$s>
            </div>',
            $background_image->sizes['featured-parallax'],
            $background_video,
            ( ! empty( $background_mobile->sizes['featured-tablet'] ) ? 'data-mobile="' . esc_url( $background_mobile->sizes['featured-tablet'] ) . '"' : '' )
        );
    }

    /**
     * Build a list of helper classes for module attributes passed into this method
     *
     * @param string $width
     * @param string $align
     * @param string $text_color
     *
     * @return string
     */
    public static function getModuleAttributeClasses( $width = '', $align = 'centered', $text_color = '#252525' ) {
        // set text align option
        $classes = $width ? 'content--' . $width : '';

        // set text align option
        $classes .= $align ? ' content--' . $align : '';

        // set text color contrast class
        $classes .= ' text--' . ThemeStyles::colorLightOrDark( $text_color, 'light', 'dark' );

        return $classes;
    }

    /**
     * Get Button Alignment options
     *
     * @param $group_prefix
     *
     * @return array
     */
    public static function getButtonAlignmentOptions( $group_prefix ) {

        $alignmentOptions = [
            ''          => __( 'Theme Default', 'reach' ),
            'left'      => __( 'Left', 'reach' ),
            'center'    => __( 'Center', 'reach' ),
            'right'     => __( 'Right', 'reach' )
        ];

        if ( isset( $_GET['post'] ) ) {
            $id                  = $_GET['post'];
            $page_meta           = Util::getPostMeta( $id );
            $currentAlignment    = Util::getField( $group_prefix . 'button_alignment', $page_meta, '' );

            if ( ! empty( $currentAlignment ) ) {
                unset(  $alignmentOptions[''] );
            }
        }

        return $alignmentOptions;
    }

    /**
     * Build the button markup and return the output
     *
     * @param $data
     * @param $class
     * @param $background
     * @param $tweenClasses
     * @param $align
     *
     * @return string
     */
    public static function outputButtonMarkup( $data, $class = '', $background = [], $tweenClasses = '', $align = '') {
        $output = '';
        // check that we have a URL option set for our button before we output it
        if ( empty( $data['url'] ) || empty( $data['text'] ) ) {
            return $output;
        }

        $text_color = ! empty( $background['text_color'] ) ? ThemeStyles::colorLightOrDark( $background['text_color'], 'light', 'dark' ) : 'dark';

        $button_url    = $data['url'];
        if (preg_match('/company-phone/i', $button_url)) {
            $button_url = do_shortcode($button_url);
            $button_url = preg_replace("~\D~", '', $button_url);
            $button_url = substr($button_url,0,10);
            $button_url = 'tel:'. $button_url;
        }
        $button_text   = isset( $data['text'] ) ? esc_html( $data['text'] ) : __( 'Learn More', 'reach' );
        $button_target = $data['external'] ? 'target="_blank"' : '';
        $button_class  = 'btn--' . $text_color;

        $button_align = ! empty( $align ) ? $class . '__button--' . $align : '';

        $output .= '<div class="' . $class . '__button ' . $class . '__button--' . $text_color . ' ' . $tweenClasses . ' ' . $button_align . '">';
        $output .= '<a class="btn ' . $button_class . '" href="' . esc_url( $button_url ) . '" ' . $button_target . '>' . $button_text . '</a>';
        $output .= '</div>';

        return $output;
    }

    /**
     * Loop through all enabled page modules and ensure the post meta matches the currently assigned page ID.
     *
     * @param array $modules
     */
    public function updatePageModuleMeta( $modules = [] ) {
        global $wpdb;
        // Loop through modules assigned to all pages.
        foreach ( $modules as $id => $module ) {
            if ( empty( $module ) ) {
                continue;
            }
            // loop through modules assigned to this specific page
            foreach ( $module as $group ) {
                $group_key  = strstr( $group, 'group' );
                $group_meta = $wpdb->get_results(
                    "SELECT meta_id
                    FROM wp_posts p1
                    INNER JOIN wp_postmeta p2
                      ON (p1.ID = p2.post_id)
                    WHERE (p2.meta_key LIKE '%$group_key%')
                      AND p1.post_status='publish'"
                );

                if ( ! empty( $group_meta ) ) {
                    foreach ( $group_meta as $row ) {
                        $this->updateModuleRow( $id, $row );
                    }
                }
            }
        }
    }

    /**
     * Update the post_id value for the key passed into this function to allow modules to be moved between pages.
     *
     * @param $id
     * @param $row
     */
    private function updateModuleRow( $id, $row ) {
        global $wpdb;

        $wpdb->query(
            $wpdb->prepare(
                "UPDATE $wpdb->postmeta SET post_id=%d WHERE meta_id='%s'",
                $id,
                $row->meta_id
            )
        );
    }
}
