<?php

/*
Plugin Name: Dance-X-Connector
Plugin URI: https://web-helferlein.ch
Update URI: https://pus.web-show.ch/check-dancex.php
Description: Verbindet Wordpress mit dem zentralen Dance-X-Backend.
Version: 2.2.0
Requires at least: 6.0
Requires PHP: 8.0.30
Author: Web-Helferlein
Author URI: https://web-helferlein.ch
License: GPL v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.txt
*/

// Exit if accessed directly
if (!defined('ABSPATH')) {
    //prevent direct access of plugin
    die('No direct access!');
}

if (!class_exists('DXPlugin')) {

    class DXPlugin
    {
        public function __construct()
        {
            define('DANCE_X_PLUGIN_PATH', plugin_dir_path(__FILE__));
            define('DANCE_X_PLUGIN_MAIN_FILE', DANCE_X_PLUGIN_PATH . basename(__FILE__));
            define('DANCE_X_PLUGIN_SLUG', basename(__DIR__));
            define('DANCE_X_PLUGIN_FOLDER_AND_SLUG', DANCE_X_PLUGIN_SLUG . "/" . basename(__FILE__));

            define('DANCE_X_PLUGIN_UPDATE_DATA_CRON_JOB_EVENT_NAME', 'dx_automatic_data_update_event');

            //require = dont't checks one insertion - it is essential for the execution of the script. If the specified file cannot be included (for example, if the file is missing), it will result in a fatal error, and the script will be terminated
            //require_once = checks for only one insertion - it is essential for the execution of the script. If the specified file cannot be included (for example, if the file is missing), it will result in a fatal error, and the script will be terminated
            //include_once = checks for only one insertion - if the specified file cannot be included, it will generate a warning, but the script will continue to execute

            //we want to use CarbonFields here: https://carbonfields.net
            require_once(DANCE_X_PLUGIN_PATH . '/vendor/autoload.php');

            require_once(DANCE_X_PLUGIN_PATH . '/includes/options-page.php');
            require_once(DANCE_X_PLUGIN_PATH . '/includes/utilities.php');
            require_once(DANCE_X_PLUGIN_PATH . '/includes/checkdb-page.php');
            require_once(DANCE_X_PLUGIN_PATH . '/includes/operations-page.php');
            require_once(DANCE_X_PLUGIN_PATH . '/includes/data-access.php');
            require_once(DANCE_X_PLUGIN_PATH . '/includes/jetformbuilder-logic.php');
            require_once(DANCE_X_PLUGIN_PATH . '/includes/backend-communication.php');
            require_once(DANCE_X_PLUGIN_PATH . '/includes/data-objects.php');
            require_once(DANCE_X_PLUGIN_PATH . '/includes/wp-auto-updater.php');

            register_activation_hook(__FILE__, array($this, 'activatePlugin'));
            register_deactivation_hook(__FILE__, array($this, 'deactivatePlugin'));

            add_action('admin_enqueue_scripts', array($this, 'enqueue_plugin_scripts'));
            add_action('admin_menu', array($this, 'init_menus'));

            add_action('rest_api_init', array($this, 'create_quote_endpoint'));
            add_action('rest_api_init', array($this, 'create_sync_endpoint'));

            add_action('init', array($this, 'add_custom_post_types'));

            add_action(DANCE_X_PLUGIN_UPDATE_DATA_CRON_JOB_EVENT_NAME, array($this, 'processEvidenceSync'));

            add_filter('cron_schedules', array($this, 'add_new_cron_job_intervals'));

            $update_kursbelegung = get_option('_dxcp_update_kursbelegung', 'no') == 'yes';
            if ($update_kursbelegung) {
                add_action('template_redirect', array($this, 'updateKursbelegungBeforePageRenders'));
            }

            $this->init_update_cronjob();
        }

        function init_update_cronjob()
        {
            $update_cronjob_enabled = get_option('_dxcp_update_cronjob_enabled', 'no') == 'yes';
            $update_cronjob_starttime = get_option('_dxcp_update_cronjob_starttime');

            if ($update_cronjob_enabled) {

                $update_cronjob_run_every_minute = get_option('_dxcp_update_cronjob_run_every_minute', 60);

                $timestampToStart = time();
                if ($update_cronjob_starttime != false) {
                    $timestampToStart = strtotime($update_cronjob_starttime);
                }

                if (!wp_next_scheduled(DANCE_X_PLUGIN_UPDATE_DATA_CRON_JOB_EVENT_NAME)) {

                    //der Cron-Job wurde noch nie gescheduled also kann er einfach gemäss Einstellungen erstellt werden
                    //die Einstellung von $recurrence muss im System vorhanden sein (vgl. add_new_cron_job_intervals($schedules) weiter unten)

                    wp_schedule_event($timestampToStart, "dxcp_every_" . $update_cronjob_run_every_minute . "_minute", DANCE_X_PLUGIN_UPDATE_DATA_CRON_JOB_EVENT_NAME);

                    //leider muss mitgespeichert werden, in welchem Takt (recurrence) / Startzeit der Cron-Job läuft, damit dieser später rekonfiguriert werden kann, wenn etwas umgestellt wurde
                    //WP speichert den Takt (recurrence) / Startzeit leider nicht sauber mit ab, was es im Nachhinein sehr schwierig machen würde diese Info zu rekonstruieren
                    update_option('dxcp_current_recurrence', $update_cronjob_run_every_minute);
                    update_option('dxcp_current_cronjob_starttime', $timestampToStart);
                } else {

                    //der Cron-Job existiert bereits - jetzt muss überprüft werden, ob der/die Takt (recurrence) / Startzeit umgestellt wurde
                    $current_recurrence = get_option('dxcp_current_recurrence');
                    $current_cronjob_starttime = get_option('dxcp_current_cronjob_starttime');

                    //checken ob der Takt (recurrence) oder Startzeit ungleich ist
                    if ($update_cronjob_run_every_minute != $current_recurrence || $timestampToStart != $current_cronjob_starttime) {

                        //bestehende Cron-Job-Events löschen...
                        wp_clear_scheduled_hook(DANCE_X_PLUGIN_UPDATE_DATA_CRON_JOB_EVENT_NAME);

                        //...und mit neuem Takt (recurrence) / Startzeit wiedererstellen...
                        wp_schedule_event($timestampToStart, "dxcp_every_" . $update_cronjob_run_every_minute . "_minute", DANCE_X_PLUGIN_UPDATE_DATA_CRON_JOB_EVENT_NAME);

                        //...und den aktuellen Takt (recurrence) / Startzeit speichern
                        update_option('dxcp_current_recurrence', $update_cronjob_run_every_minute);
                        update_option('dxcp_current_cronjob_starttime', $timestampToStart);
                    }
                }
            } else {
                //wenn der Cron-Job ausgestellt ist alle DanceX-Cron-Jobs löschen
                wp_clear_scheduled_hook(DANCE_X_PLUGIN_UPDATE_DATA_CRON_JOB_EVENT_NAME);
            }
        }

        function add_new_cron_job_intervals($schedules)
        {
            $schedules['dxcp_every_1_minute'] = array(
                'interval' => 1 * 60,
                'display'  => 'Every 1 minute'
            );

            $schedules['dxcp_every_5_minute'] = array(
                'interval' => 5 * 60,
                'display'  => 'Every 5 Minutes'
            );

            $schedules['dxcp_every_10_minute'] = array(
                'interval' => 10 * 60,
                'display'  => 'Every 10 Minutes'
            );

            $schedules['dxcp_every_30_minute'] = array(
                'interval' => 30 * 60,
                'display'  => 'Every 30 Minutes'
            );

            $schedules['dxcp_every_60_minute'] = array(
                'interval' => 60 * 60,
                'display'  => 'Every 60 Minutes'
            );

            $schedules['dxcp_every_720_minute'] = array(
                'interval' => 60 * 60 * 12,
                'display'  => 'Every 12 Hours'
            );

            $schedules['dxcp_every_1440_minute'] = array(
                'interval' => 60 * 60 * 24,
                'display'  => 'Every 24 Hours'
            );

            return $schedules;
        }

        function add_custom_post_types()
        {
            $dxTypes = DXType::GetAllTypes();

            $show_cpt = get_option('_dxcp_show_cpt', 'no') == 'yes';

            foreach ($dxTypes as $dxType) {

                if (!$dxType->hasSinglePost)
                    continue;

                $args = array(
                    'public' => true,
                    'label'  => $dxType->cptDisplayName,
                    'show_ui' => $show_cpt,
                    'show_in_menu' => 'dxcp_cpt',
                    'description' => "CPT to use for CCT {$dxType->typeEnum->value} 'Related Post Type'-definition."
                );

                register_post_type($dxType->cptTypeName, $args);
            }
        }

        function activatePlugin() {}

        function deactivatePlugin() {}

        function processEvidenceSync()
        {
            $syncer = new DXEvidenceSync();
            $result = $syncer->processSync();

            if (!$result) {
                error_log("Es gab Probleme beim automatischen Evidence-Sync per Cron-Job!");
            }
        }

        function enqueue_plugin_scripts()
        {
            //only insert bootstrap if need if i am "in my plugin" - otherwise even other parts of WP are affected
            if (
                is_admin() && isset($_GET['page']) &&
                ($_GET['page'] === 'dxcp_menu' ||
                    $_GET['page'] === 'dxcp_menu' ||
                    $_GET['page'] === 'dxcp_operations' ||
                    $_GET['page'] === 'dxcp_checkdb')
            ) {
                wp_enqueue_style('bootstrap-css', 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css'); // Use the correct path or CDN
                wp_enqueue_style('fontawesome-css', plugins_url('/deps/fontawesome/css/all.min.css', __FILE__));
            }

            wp_enqueue_style('dxcp-admin-style', plugins_url('/admin/css/dxcp-admin.css', __FILE__));
            wp_enqueue_style('dxcp-loader', plugins_url('/admin/css/dxcp-loader.css', __FILE__));

            wp_enqueue_script('dxcp-admin-script', plugins_url('/admin/js/dxcp-admin.js', __FILE__), array('jquery'), '1.0');

            // Pass PHP data to JavaScript
            wp_localize_script('dxcp-admin-script', 'dxcp_admin_script_data', array(

                //was needed for first version of rest-api-call
                'ajax_url' => admin_url('admin-ajax.php'),
                'action' => 'call_github',

                //better version if registered api-path
                'rest_api_quote_url' => rest_url('dxcp/v1/quote'),
                'nonce' => wp_create_nonce('dxcp_nonce')
            ));
        }

        function init_menus()
        {
            add_menu_page(
                'Dance-X-Connector',
                'Dance-X-Connector',
                'manage_options',
                'dxcp_menu',
                array($this, 'plugin_overview_html'),
                'dashicons-superhero'
            );

            $show_cpt = get_option('_dxcp_show_cpt', 'no') == 'yes';
            if ($show_cpt) {
                add_menu_page(
                    'CPTs',
                    'CPTs',
                    'manage_options',
                    'dxcp_cpt',
                    function () {
                        //empty callback - is only hook-point for the CPT menus
                    },
                    'dashicons-list-view'
                );
            }

            add_submenu_page(
                'dxcp_menu',
                'Operationen',
                'Operationen',
                'manage_options',
                'dxcp_operations',
                array('DXOperationPage', 'operations_html')
            );

            add_submenu_page(
                'dxcp_menu',
                'Überprüfe DB-Schema',
                'Überprüfe DB-Schema',
                'manage_options',
                'dxcp_checkdb',
                array('DXCheckDbPage', 'checkdb_html')
            );
        }

        function create_quote_endpoint()
        {
            register_rest_route('dxcp/v1', '/quote', array(
                "methods" => 'GET',
                "callback" => array($this, "handleGetQuote"),
                "permission_callback" => "__return_true"
            ));
        }

        function handleGetQuote()
        {
            $category = "";

            if (isset($_GET['cat'])) {
                $category = $_GET['cat'];
            }

            $quote = $this->getQuote($category);
            wp_send_json($quote);
        }

        function create_sync_endpoint()
        {
            register_rest_route('dxcp/v1', '/syncData', array(
                "methods" => 'GET',
                "callback" => array($this, "handleSyncData"),
                "permission_callback" => "__return_true"
            ));
        }

        function handleSyncData()
        {
            $result = array(
                "message" => ""
            );

            try {

                if (!isset($_GET['token'])) {
                    $result['message'] = "Query-Param 'token' not sent!";
                    wp_send_json($result, 400);
                }

                $apiKeyFromOptions =  get_option('_dxcp_apikey');
                $tokenFromRequest = $_GET['token'];

                $isGivenTokenCorrect = strcasecmp($apiKeyFromOptions, $tokenFromRequest) == 0;
                if (!$isGivenTokenCorrect) {
                    $result['message'] = "Query-Param 'token' does not match the one setup in DB!";
                    wp_send_json($result, 400);
                }

                $syncer = new DXEvidenceSync();
                $syncResult = $syncer->processSync();

                if ($syncResult) {
                    $result['message'] = "DataSync successfully processed :-)";
                    wp_send_json($result, 200);
                } else {
                    $result['message'] = "DataSync failed (see logs for more info)!";
                    wp_send_json($result, 500);
                }
            } catch (\Throwable $th) {
                $result['message'] = "Unhandled Exception happened (see logs for more info)!";
                error_log("An unhandled exception occured while processing the data-sync over GET-Call. Ex-Message: " . $th->getMessage());
                wp_send_json($result, 500);
            }
        }

        function updateKursbelegungBeforePageRenders()
        {
            $kursnummer = 0;

            try {
                $requestUri = $_SERVER['REQUEST_URI'];
                $areQueryParamsAbsent = empty($_SERVER['QUERY_STRING']);

                $splittedUri = DXUtil::splitRequestUri($requestUri);
                $pvCount = count($splittedUri['path_vars']);

                //wenn der Pfad sowas wie "*/kurs/salsa-1" ohne Query-Parameter ist, dann die Kursbelegung updaten
                if ($pvCount >= 2 &&  strcasecmp($splittedUri['path_vars'][$pvCount - 2], 'kurs') == 0 && $areQueryParamsAbsent) {

                    $da = new DXDataAccess();

                    $kursSlug = $splittedUri['path_vars'][$pvCount - 1];
                    $post = get_page_by_path($kursSlug, OBJECT, 'kurs');

                    if (!empty($post)) {
                        $postId = $post->ID;
                        $kursnummer = $da->getKursnummerByPostId($postId);

                        if (!empty($kursnummer)) {
                            $backendComm = new DXBackendCommunication();
                            $kursbelegung = $backendComm->getKursbelegung($kursnummer);
                            $da->updateKursbelegung($kursnummer, $kursbelegung);
                        }
                    }
                }
            } catch (\Throwable $th) {
                error_log("Es ist eine Exception aufgetreten während versucht wurde für die Kursnummer $kursnummer die Kursbelegung zu updaten, bevor die Seite zum Web-Client gesendet wird. Ex-Message: " . $th->getMessage());
            }
        }

        function plugin_overview_html()
        {
            // check user capabilities
            if (!current_user_can('manage_options')) {
                return;
            }

            $quote = $this->getQuote("");

?>
            <div class="wrap">

                <div class="container-fluid mt-3">

                    <h1><?php echo get_admin_page_title() . " (" . DXUtil::getPluginData()['Version'] . ")"; ?> </h1>

                    <div class="row mt-2">

                        <p>Diese Plugin wurde/wird entwickelt von <a href="https://web-helferlein.ch/" target="_blank">Web-Helferlein.ch</a></p>

                        <p>Bei Fragen, Anregungen oder Problemen einfach eine E-Mail schreiben an <a href="mailto:info@web-helferlein.ch">info@web-helferlein.ch</a></p>

                    </div>

                    <div class="row mb-3">
                        <div class="col-3">
                            <hr>

                            <label for="catChooser" class="form-label">Zitat-Kategorie</label>

                            <select class="form-select" id="catChooser">
                                <option value="" selected>all</option>
                                <option value="age">age</option>
                                <option value="alone">alone</option>
                                <option value="amazing">amazing</option>
                                <option value="anger">anger</option>
                                <option value="architecture">architecture</option>
                                <option value="art">art</option>
                                <option value="attitude">attitude</option>
                                <option value="beauty">beauty</option>
                                <option value="best">best</option>
                                <option value="birthday">birthday</option>
                                <option value="business">business</option>
                                <option value="car">car</option>
                                <option value="change">change</option>
                                <option value="communication">communication</option>
                                <option value="computers">computers</option>
                                <option value="cool">cool</option>
                                <option value="courage">courage</option>
                                <option value="dad">dad</option>
                                <option value="dating">dating</option>
                                <option value="death">death</option>
                                <option value="design">design</option>
                                <option value="dreams">dreams</option>
                                <option value="education">education</option>
                                <option value="environmental">environmental</option>
                                <option value="equality">equality</option>
                                <option value="experience">experience</option>
                                <option value="failure">failure</option>
                                <option value="faith">faith</option>
                                <option value="family">family</option>
                                <option value="famous">famous</option>
                                <option value="fear">fear</option>
                                <option value="fitness">fitness</option>
                                <option value="food">food</option>
                                <option value="forgiveness">forgiveness</option>
                                <option value="freedom">freedom</option>
                                <option value="friendship">friendship</option>
                                <option value="funny">funny</option>
                                <option value="future">future</option>
                                <option value="god">god</option>
                                <option value="good">good</option>
                                <option value="government">government</option>
                                <option value="graduation">graduation</option>
                                <option value="great">great</option>
                                <option value="happiness">happiness</option>
                                <option value="health">health</option>
                                <option value="history">history</option>
                                <option value="home">home</option>
                                <option value="hope">hope</option>
                                <option value="humor">humor</option>
                                <option value="imagination">imagination</option>
                                <option value="inspirational">inspirational</option>
                                <option value="intelligence">intelligence</option>
                                <option value="jealousy">jealousy</option>
                                <option value="knowledge">knowledge</option>
                                <option value="leadership">leadership</option>
                                <option value="learning">learning</option>
                                <option value="legal">legal</option>
                                <option value="life">life</option>
                                <option value="love">love</option>
                                <option value="marriage">marriage</option>
                                <option value="medical">medical</option>
                                <option value="men">men</option>
                                <option value="mom">mom</option>
                                <option value="money">money</option>
                                <option value="morning">morning</option>
                                <option value="movies">movies</option>
                                <option value="success">success</option>
                            </select>
                        </div>
                    </div>

                    <div class="row">
                        <hr>
                        <div class="col-1 align-self-center text-center">

                            <a href="#" title="neues Zitat laden" class="button button-large" style="font-size:24px;" onclick="loadQuote(jQuery('figure'), jQuery('#catChooser'));">
                                <i class="fa-solid fa-rotate-right fa-2xl" style="color: #0080ff;"></i>
                            </a>
                        </div>

                        <div class="col-11">

                            <figure class="text-center">
                                <blockquote class="blockquote">
                                    <p id="qquote"><?php echo $quote->quote ?></p>
                                </blockquote>
                                <figcaption class="blockquote-footer">
                                    <span id="qauthor"><?php echo $quote->author ?></span> <cite id="qcategory">(<?php echo $quote->category ?>)</cite>
                                </figcaption>
                            </figure>

                        </div>
                        <hr>
                    </div>

                    <div class="row mt-3">
                        <h1>Hilfestellungen</h1>
                        <p>Um die Datensynchronisierung mit dem Dance-X-Backend "von aussen" zu starten kann die folgende URL aufgerufen werden:</p>
                        <p>[basisUrl]<span class="fw-bold">/wp-json/dxcp/v1/syncData<span style="color:darkred;">?token=ApiKey</span></span></p>
                        <p>Dabei muss der <span style="color:darkred;" class="fw-bold">ApiKey</span> mitgegeben werden, der in den Optionen eingestellt ist → einfaches Security-Element</p>
                        <p>Der GET-Aufruf kann in jedem beliebigem Browser bewerkstelligt werden.</p>
                    </div>

                </div>
            </div>
<?php
        }

        private function getQuote(string $category)
        {
            $quote = new stdClass();

            $quote->quote = "a quote";
            $quote->author = "a author";
            $quote->category = "a category";

            // Set up the request parameters
            $request_args = array(
                'method'    => 'GET',
                'headers'   => array(
                    'x-api-key' => 'pXP6/njxQ6sUiVe/rsqSIA==VrdE2EOYdneNNtsm',
                ),
            );

            //https://api-ninjas.com vom Matz (Spielerei!!!)
            $response = wp_remote_get("https://api.api-ninjas.com/v1/quotes?category={$category}", $request_args);
            $http_code = wp_remote_retrieve_response_code($response);

            if (!is_wp_error($response) && $http_code == 200) {
                $data = json_decode(wp_remote_retrieve_body($response), false);
                $quote =  $data[0];
            }
            return $quote;
        }
    }

    $dxPlugin = new DXPlugin();
}
