<?php

namespace Reach\App;

use Reach\App\Interfaces\WordPressHooks;

/**
 * Class SEO
 *
 * addHooks()
 * rewriteRules()
 * rewriteTemplates()
 * rewritePreTitlePage()
 * rewriteTitlePage()
 * isPageSitemap()
 * outputSitemapList()
 * getSitePostsByType()
 * getPostTermsByTaxonomy()
 * getSiteAuthors()
 *
 * @package Reach\App
 */
class SEO implements WordPressHooks {

    /**
     * Add class hooks.
     */
    public function addHooks() {
        add_action( 'init', [ $this, 'rewriteRules' ] );
        add_action( 'template_include', [ $this, 'rewriteTemplates' ] );
        add_filter( 'pre_get_document_title', [ $this, 'rewritePreTitlePage' ], 99, 1 );
        add_filter( 'wpseo_opengraph_title', [ $this, 'rewritePreTitlePage' ], 99, 1 );
        add_filter( 'wpseo_twitter_title', [ $this, 'rewritePreTitlePage' ], 99, 1 );
        add_filter( 'document_title_parts', [ $this, 'rewriteTitlePage' ] );
    }


    /**
     * Handle the sitemap rewrite rules
     *
     * @since 0.9.0
     */
    public function rewriteRules() {
        add_rewrite_endpoint( 'sitemap', EP_PERMALINK | EP_PAGES );

        // sitemap rewrite
        add_rewrite_rule( 'sitemap', 'index.php?pagename=sitemap', 'top' );

        // allow custom query string variable of sitemap
        add_rewrite_tag( '%sitemap%', '([^/]*)' );
    }

    /**
     * Handle the sitemap rewrite template
     *
     * @param $template
     *
     * @return string
     */
    public function rewriteTemplates( $template ) {
        // override template if we're on the sitemap view
        if ( 'sitemap' === get_query_var( 'name' ) ) {
            status_header( 200 );

            return locate_template( 'templates/sitemap.php' );
        }

        return $template;
    }

    /**
     * Set a page title for the custom endpoint to overwrite yoast SEO filter
     *
     * @since 1.6.0
     */
    public function rewritePreTitlePage( $title ) {
        if ( 'sitemap' === get_query_var( 'name' ) ) {
            $title = sprintf(
                '%s - %s',
                $this->getPageSitemapTitle(),
                get_bloginfo( 'name' )
            );
        }

        return $title;
    }

    /**
     * Set a page title for the custom endpoint
     *
     * @since 1.6.0
     */
    public function rewriteTitlePage( $title ) {
        if ( 'sitemap' === get_query_var( 'name' ) ) {
            $title['title'] = $this->getPageSitemapTitle();
        }

        return $title;
    }

    /**
     * Check if the current page is our Sitemap
     *
     * @return bool
     */
    public static function isPageSitemap() {
        global $wp_query;

        if ( ! isset( $wp_query ) ) {
            _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' );

            return false;
        }

        if ( 'sitemap' !== $wp_query->query_vars['name'] ) {
            return false;
        }

        return true;
    }

    /**
     * Check for a dynamic page and output the correct page title.
     *
     * @param $default
     *
     * @return mixed
     */
    public function getPageSitemapTitle( $default = '' ) {
        $post_id = get_the_ID();
        $default = $default ? esc_attr( $default ) : __( 'Sitemap', 'reach' );

        return $post_id ? get_the_title( $post_id ) : $default;
    }

    /**
     * Build and return a generated html sitemap
     *
     * @return string
     */
    public function outputSitemapList() {
        $lists = '';

        // get pages list
        $lists .= $this->getSitePostsByType( 'page' );

        return $lists;
    }

    /**
     * Generate an unordered list of published pages and return the string
     *
     * @param string $post_type
     * @param string $title
     *
     * @return string
     */
    public function getSitePostsByType( $post_type = 'page', $title = '' ) {
        $lists      = '';
        $items_list = '';
        $title      = $title ?: __( 'Pages', 'reach' );

        // check for and get pages
        $posts_query = new \WP_Query( [
            'post_type'      => $post_type,
            'posts_per_page' => 500,
            'no_found_rows'  => true,
            'orderby'        => 'title',
            'order'          => 'ASC',
            'post__not_in'   => [ ( get_the_ID() ?: '' ) ]
        ] );

        // loop through posts and check for a no index seo meta
        if ( $posts_query->have_posts() ) {
            // split our posts into equal column arrays
            $items_per_column = ceil( count( $posts_query->posts ) / 3 );
            $post_columns     = array_chunk( $posts_query->posts, $items_per_column );

            // loop through our column lists
            foreach ( $post_columns as $column_items ) {
                $list_column = '';

                foreach ( $column_items as $post ) {
                    $no_follow = get_post_meta( $post->ID, '_yoast_wpseo_meta-robots-noindex', true );
                    if ( $no_follow ) {
                        continue;
                    }
                    // add post list item
                    $list_column .= sprintf(
                        '<li class="post_item post-item-%d"><a href="%s">%s</a></li>',
                        $post->ID,
                        esc_url( get_permalink( $post->ID ) ),
                        $post->post_title
                    );
                }

                // add column with post items to markup output
                $items_list .= sprintf( '<div class="col-sm-4"><ul>%s</ul></div>', $list_column );
            }

            $lists .= sprintf( '<div class="sitemap__row sitemap__row--%s"><h4>%s</h4><div class="row">%s</div></div>', $post_type, $title, $items_list );
        }

        return $lists;
    }

    /**
     * Generate an unordered list of terms defined on call and return the string
     *
     * @param string $taxonomy
     * @param $title
     *
     * @return string
     */
    public function getPostTermsByTaxonomy( $taxonomy = 'category', $title ) {
        $lists      = '';
        $terms_list = '';
        $title      = $title ?: __( 'Categories', 'reach' );

        // check for and get pages
        $categories_query = new \WP_Term_Query( [
            'taxonomy'   => $taxonomy,
            'orderby'    => 'name',
            'order'      => 'ASC',
            'hide_empty' => false,
        ] );

        if ( ! empty( $categories_query->terms ) ) {
            // split our terms into equal column arrays
            $terms_per_column = ceil( count( $categories_query->terms ) / 3 );
            $term_columns     = array_chunk( $categories_query->terms, $terms_per_column );

            // loop through our column lists
            foreach ( $term_columns as $column_items ) {
                $list_column = '';

                foreach ( $column_items as $term ) {
                    // add post list item
                    $list_column .= sprintf(
                        '<li class="term_item term-item-%d"><a href="%s">%s</a></li>',
                        $term->term_id,
                        esc_url( get_term_link( $term->term_id ) ),
                        $term->name
                    );
                }

                // add column with post items to markup output
                $terms_list .= sprintf( '<div class="col-sm-4"><ul>%s</ul></div>', $list_column );
            }

            $lists .= sprintf( '<div class="sitemap__row sitemap__row--%s"><h4>%s</h4><div class="row">%s</div></div>', $taxonomy, $title, $terms_list );
        }

        return $lists;
    }

    /**
     * Generate an unordered list of site authors and return the string
     *
     * @return string
     */
    public function getSiteAuthors() {
        $seo_options = get_option( 'wpseo_xml' ) ?: [];
        $editors     = get_users( [
            'role' => 'editor',
        ] );
        $lists       = '';
        $users_list  = '';

        // check for and get authors
        if ( $editors && ! empty( $seo_options['disable_author_sitemap'] ) && $seo_options['disable_author_sitemap'] ) {
            // split our users into equal column arrays
            $users_per_column = ceil( count( $editors ) / 3 );
            $user_columns     = array_chunk( $editors, $users_per_column );

            // loop through our column lists
            foreach ( $user_columns as $column_items ) {
                $list_column = '';

                foreach ( $column_items as $user ) {
                    // add post list item
                    $list_column .= sprintf(
                        '<li class="user_item user-item-%d"><a href="%s">%s</a></li>',
                        $user->ID,
                        esc_url( get_author_posts_url( $user->ID ) ),
                        $user->display_name
                    );
                }

                // add column with post items to markup output
                $users_list .= sprintf( '<div class="col-sm-4"><ul>%s</ul></div>', $list_column );
            }

            $lists .= sprintf( '<div class="sitemap__row sitemap__row--authors"><h4>%s</h4><div class="row">%s</div></div>', __( 'Authors', 'reach' ), $users_list );
        }

        return $lists;
    }
}
