<?php

namespace ReachAudit\App\Http;

use ReachAudit\App\Interfaces\WordPressHooks;
use ReachAudit\App\Fields\Util;
use Reach\App\Core\Transients;

/**
 * Class ModulesController\Http
 *
 * @package ReachAudit\App\Http
 */
class ModulesController implements WordPressHooks {

    /**
     * Add class hooks.
     */
    public function addHooks() {
        add_action( 'rest_api_init', [ $this, 'registerModulesRoute' ] );
    }

    /**
     * Register our custom search endpoint to handle use and thank-you search results
     */
    public function registerModulesRoute() {
        register_rest_route( 'reach/audit/v1', '/modules/check', [
            'methods'  => 'GET',
            'callback' => [ $this, 'checkForDuplicateModules' ],
        ] );
        register_rest_route( 'reach/audit/v1', '/modules/refresh', [
            'methods'  => 'POST',
            'callback' => [ $this, 'duplicatePageModule' ],
        ] );
    }

    /**
     * Register REST endpoints
     *
     * @param \WP_REST_Request $request
     *
     * @return mixed|\WP_REST_Response
     */
    public function checkForDuplicateModules( \WP_REST_Request $request ) {
        $modules = $this->getAllPageModules();

        $response[0] = $this->checkModuleDuplicates( $modules );

        return rest_ensure_response( $response );
    }

    /**
     * Get all active page modules in the Options table and build an array of IDs
     *
     * @return array
     */
    public function getAllPageModules() {
        $options = Util::getSiteOptions();
        $modules = [];
        foreach ( $options as $key => $option ) {
            $page_id = explode( 'page_modules_', $key );
            if ( ( substr( $key, 0, 13 ) === 'page_modules_' ) && is_array( $option ) ) {
                foreach ( $option as $module ) {
                    if ( ! empty( $module ) ) {
                        $group_key = strstr( $module, 'group' );
                        $modules[] = [
                            'id'   => $group_key,
                            'page' => (int) $page_id[1]
                        ];
                    }
                }
            }
        }

        return $modules;
    }

    /**
     * Loop through array of modules and count any duplicate IDs
     *
     * @param array $modules
     *
     * @return array
     */
    public function checkModuleDuplicates( $modules = [] ) {
        $count      = 0;
        $duplicates = [];
        if ( empty( $modules ) ) {
            return $duplicates;
        }

        foreach ( $modules as $key => $module ) {
            $duplicates[] = $module['id'];
        }

        // loop through array of modules
        foreach ( $modules as $key => $module ) {
            // first, remove current module ID, then check if a duplicate exists in the current array
            unset( $duplicates[ $key ] );
            $modules[ $key ]['status'] = __( 'OK', 'reach-audit' );
            if ( in_array( $module['id'], $duplicates ) ) {
                $count ++;
                $modules[ $key ]['status'] = __( 'Duplicate', 'reach-audit' );
            }
        }

        return [
            'duplicate_modules' => $count,
            'modules'           => $modules
        ];
    }

    /**
     * Duplicate all origin module meta passed into our endpoint with the defined clone ID
     *
     * @param \WP_REST_Request $request
     *
     * @return array
     */
    public function duplicatePageModule( \WP_REST_Request $request ) {
        // Or via the helper method:
        $post_id     = $request->get_param( 'page_id' );
        $origin      = $request->get_param( 'origin' );
        $clone       = $request->get_param( 'clone' );
        $origin_key  = urldecode( $origin );
        $clone_key   = urldecode( $clone );
        $response[0] = [
            'rows_updated' => 0
        ];

        if ( ! $origin ) {
            return new \WP_Error( 'rest_invalid_param', __( 'Invalid parameter(s): Origin key is not defined.', 'reach-audit' ) );
        }

        if ( ! $clone ) {
            return new \WP_Error( 'rest_invalid_param', __( 'Invalid parameter(s): Clone key is not defined.', 'reach-audit' ) );
        }

        global $wpdb;
        // query for the origin meta to duplicate
        $origin_meta = $wpdb->get_results( "SELECT meta_id, post_id, meta_key, meta_value FROM $wpdb->postmeta WHERE post_id = '$post_id' AND meta_key LIKE '%$origin%'" );
        if ( ! empty( $origin_meta ) ) { // Check that we received meta data.
            // loop through the origin meta and duplicate each row with the new key.
            foreach ( $origin_meta as $row ) {
                $updated_key = str_replace( $origin_key, $clone_key, $row->meta_key );
                $meta_value  = $row->meta_value;
                if ( strpos( $meta_value, $origin_key ) !== false ) {
                    $meta_value = str_replace( $origin_key, $clone_key, $meta_value );
                }

                $wpdb->replace(
                    $wpdb->postmeta,
                    [
                        'meta_id'    => $row->meta_id,
                        'post_id'    => $post_id,
                        'meta_key'   => $updated_key,
                        'meta_value' => $meta_value
                    ],
                    [
                        '%d',
                        '%d',
                        '%s',
                        '%s'
                    ]
                );

                $response[0]['rows_updated'] ++;
            }
        }
        $this->updatePageModuleOption( $post_id, $origin_key, $clone_key );
        $this->updateEnabledPageModules();

        return rest_ensure_response( $response );
    }

    /**
     * Update page_modules array in options table with the newly created module IDs
     *
     * @param $page_id
     * @param $origin
     * @param $clone
     */
    public function updatePageModuleOption( $page_id, $origin, $clone ) {
        $key     = 'page_modules_' . $page_id;
        $options = Util::getSiteOptions();
        $modules = Util::getField( $key, $options, [] );
        foreach ( (array) $modules as $index => $module ) {
            if ( strpos( $module, $origin ) !== false ) {
                $modules[ $index ] = str_replace( $origin, $clone, $module );
            }
        }
        update_option( 'options_' . $key, $modules );
    }

    /**
     * Check all page module options in the database and compile an array of all unique modules currently registered within this site
     *
     * @return bool
     */
    public function updateEnabledPageModules() {
        global $wpdb;

        $enabled_page_modules = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE option_name LIKE 'options_page_modules_%'" );
        $page_modules         = $enabled_modules = [];
        // loop through results and build array of active modules
        foreach ( (array) $enabled_page_modules as $option ) {
            $page_id = 0;
            if ( ! empty( $option->option_name ) ) {
                $page_id = str_replace( 'options_page_modules_', '', $option->option_name );
            }
            if ( ! empty( $option->option_value ) ) {
                $values = maybe_unserialize( $option->option_value );
                foreach ( $values as $value ) {
                    if ( ! empty( $value ) ) {
                        array_push( $enabled_modules, $value );
                        $page_modules[ $page_id ][] = $value;
                    }
                }
            }
        }

        // update enabled page modules option value
        update_option( 'enabled_page_modules', array_unique( $enabled_modules ) );

        return true;
    }
}