<?php
defined('ABSPATH') or die();

/**
 * The admin-specific functionality of the plugin.
 *
 * @link       https://wwdh.de
 */

use WPOauth2\Client\OauthSettings;
use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;


class WP_Oauth2_Client_Admin_Ajax
{
    private static $admin_ajax_instance;
    private string $method;
    private object $responseJson;

    use OauthSettings;

    /**
     *
     * @var Environment $twig TWIG autoload for PHP-Template-Engine
     */
    protected Environment $twig;

    /**
     * @since    1.0.0
     * @var Wp_Oauth2_Client The main class.
     */
    protected Wp_Oauth2_Client $main;

    /**
     * The ID of this Plugin.
     *
     * @since    1.0.0
     * @access   private
     * @var      string $basename The ID of this theme.
     */
    protected string $basename;

    /**
     * @return static
     */
    public static function admin_ajax_instance(string $basename, Wp_Oauth2_Client $main, Environment $twig): self
    {
        if (is_null(self::$admin_ajax_instance)) {
            self::$admin_ajax_instance = new self($basename, $main, $twig);
        }

        return self::$admin_ajax_instance;
    }

    public function __construct(string $basename, Wp_Oauth2_Client $main, Environment $twig)
    {
        $this->main = $main;
        $this->twig = $twig;
        $this->basename = $basename;
        $this->method = filter_input(INPUT_POST, 'method', FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_HIGH);
        $this->responseJson = (object)[
            'status' => false,
            'msg' => date('H:i:s', current_time('timestamp')),
            'type' => $this->method
        ];
    }

    /**
     * @throws Exception
     */
    public function admin_ajax_handle()
    {
        if (!method_exists($this, $this->method)) {
            throw new Exception("Method not found!#Not Found");
        }

        return call_user_func_array(self::class . '::' . $this->method, []);
    }

    private function oauth_settings_handle(): object
    {
        $callback_url = filter_input(INPUT_POST, 'callback_url', FILTER_VALIDATE_URL);
        $server_url = filter_input(INPUT_POST, 'server_url', FILTER_VALIDATE_URL);
        $app_id = filter_input(INPUT_POST, 'app_id', FILTER_UNSAFE_RAW);
        $app_secret = filter_input(INPUT_POST, 'app_secret', FILTER_UNSAFE_RAW);
        $authorize_uri = filter_input(INPUT_POST, 'authorize_uri', FILTER_UNSAFE_RAW);
        $token_uri = filter_input(INPUT_POST, 'token_uri', FILTER_UNSAFE_RAW);

        if (!$callback_url || !$server_url) {
            $this->responseJson->msg = 'keine oAuth Callback Url!';

            return $this->responseJson;
        }
        $server_url = str_replace(' ', '', $server_url);
        $authorize_uri = str_replace(' ', '', $authorize_uri);
        $token_uri = str_replace(' ', '', $token_uri);
        $regEx = '@.+?/$@';
        if (preg_match($regEx, $server_url)) {
            $server_url = substr($server_url, 0, strrpos($server_url, '/'));
        }
        $regUriEx = '@.?/@';
        if (preg_match($regUriEx, $authorize_uri)) {
            $authorize_uri = substr($authorize_uri, 1);
        }
        if (preg_match($regUriEx, $token_uri)) {
            $token_uri = substr($token_uri, 1);
        }

        $settings = get_option('wp_oauth2_client_settings');
        if (!$settings['client_scopes']) {
            $settings['client_scopes'] = $this->client_default_scopes;

        }

        $settings['server_url'] = $server_url;
        $settings['authorize_uri'] = $authorize_uri;
        $settings['token_uri'] = $token_uri;
        $settings['app_id'] = $app_id;
        $settings['app_secret'] = $app_secret;
        $settings['callback_url'] = $callback_url;

        update_option('wp_oauth2_client_settings', $settings);
        $this->responseJson->status = true;
        $this->responseJson->token_url = $server_url . '/' . $token_uri;
        $this->responseJson->auth_url = $server_url . '/' . $authorize_uri;
        $server_url ? $srvUrl = true : $srvUrl = false;
        $this->responseJson->srv_url = $srvUrl;
        return $this->responseJson;
    }

    private function oauth_plugin_settings(): object
    {
        $plugin_min_role = filter_input(INPUT_POST, 'plugin_min_role', FILTER_UNSAFE_RAW);
        if (!$plugin_min_role) {
            $this->responseJson->msg = 'keine Benutzerrolle ausgewählt!';
            return $this->responseJson;
        }
        $settings = get_option('wp_oauth2_client_settings');
        $settings['selected_user_role'] = $plugin_min_role;
        update_option('wp_oauth2_client_settings', $settings);
        $this->responseJson->status = true;
        return $this->responseJson;
    }

    private function api_client_reset(): object
    {
        $pin = filter_input(INPUT_POST, 'pin', FILTER_VALIDATE_INT);
        $pin = (int)str_replace(' ', '', $pin);
        if ($pin != $this->main->get_oauth_save_pin()) {
            return $this->responseJson;
        }

        do_action($this->basename . '/remove_access_token');
        $conf = get_option($this->basename . '/oauth_api_data');
        $conf['authentifizierung'] = false;
        update_option($this->basename . '/oauth_api_data', $conf);
        delete_option($this->basename . '/refresh_token');
        $this->responseJson->redirect = admin_url('admin.php?page=wp-oauth2');

        $this->responseJson->status = true;
        return $this->responseJson;
    }

    private function api_update_scope(): object
    {
        $getApiCal = apply_filters($this->basename . '/oauth2_get_client_data', '', true);

        if (isset($getApiCal['status']) && !$getApiCal['status']) {
            $this->responseJson->title = $getApiCal['error_title'];
            $this->responseJson->msg = $getApiCal['error_msg'];
            return $this->responseJson;
        }
        apply_filters($this->basename . '/set_client_scopes', $getApiCal['scope']);
        $this->responseJson->status = true;
        $this->responseJson->redirect = admin_url('admin.php?page=wp-oauth2');
        return $this->responseJson;
    }

    private function get_api_media(): object
    {
        $this->responseJson->target = filter_input(INPUT_POST, 'target', FILTER_UNSAFE_RAW);
        $handle = filter_input(INPUT_POST, 'handle', FILTER_UNSAFE_RAW);
        $page = filter_input(INPUT_POST, 'page', FILTER_VALIDATE_INT);
        $this->responseJson->toggle = (bool)filter_input(INPUT_POST, 'toggle', FILTER_VALIDATE_INT) == 1;
        $getPage = $page ?? 1;
        $this->responseJson->handle = $handle;

        $settings = get_option('wp_oauth2_client_settings');

        $apiCall = apply_filters($this->basename . '/api_get_callback', 'media?page=' . $getPage);
        //$apiCallType = $apiCall['@type'] ?? '';
        $error = [];
        if ($apiCall['@type'] == 'hydra:Error') {
            $error = [
                'error_title' => $apiCall['hydra:title'] ?? 'unbekannt',
                'description' => $apiCall['hydra:description'] ?? 'keine Angabe'
            ];
        }
        $countAll = $apiCall['hydra:totalItems'];
        $pagination = $apiCall['hydra:view'] ?? null;
        if ($pagination) {
            $pagination = [
                'first' => $apiCall['hydra:view']['hydra:first'] ?? null,
                'last' => $apiCall['hydra:view']['hydra:last'] ?? null,
                'next' => $apiCall['hydra:view']['hydra:next'] ?? null,
                'previous' => $apiCall['hydra:view']['hydra:previous'] ?? null,
                'items' => (int)ceil($countAll / 10)
            ];
        }

        if ($error) {
            $data = [
                'error' => $error
            ];
        } else {
            $data = [
                'data' => $apiCall['hydra:member'],
                'last' => $countAll,
                'pagination' => $pagination,
                'page' => $getPage,
                'server_url' => $settings['server_url'],
            ];
        }

        try {
            $template = $this->twig->render('@templates/api-call/media-api-call.html.twig', $data);
            $this->responseJson->template = $this->html_compress_template($template);
        } catch (LoaderError|SyntaxError|RuntimeError $e) {
            $this->responseJson->msg = $e->getMessage();
            return $this->responseJson;
        } catch (Throwable $e) {
            $this->responseJson->msg = $e->getMessage();
            return $this->responseJson;
        }
        //print_r($apiCall);
        $this->responseJson->status = true;
        return $this->responseJson;
    }

    private function get_api_product(): object
    {
        $this->responseJson->target = filter_input(INPUT_POST, 'target', FILTER_UNSAFE_RAW);
        $this->responseJson->toggle = (bool)filter_input(INPUT_POST, 'toggle', FILTER_VALIDATE_INT) == 1;
        $this->responseJson->handle = filter_input(INPUT_POST, 'handle', FILTER_UNSAFE_RAW);
        $apiCall = apply_filters($this->basename . '/api_get_callback', 'product?is_show_api=1');
        $error = [];
        $mitLizenz = [1, 2];
        $themes = [];
        $child = [];
        $pml = [];
        $pol = [];
        $tol = [];
        $data = [];
        if ($apiCall['@type'] == 'hydra:Error') {
            $error = [
                'error_title' => $apiCall['hydra:title'] ?? 'unbekannt',
                'description' => $apiCall['hydra:description'] ?? 'keine Angabe'
            ];
        }
        if ($error) {
            $data = [
                'error' => $error
            ];
        } else {
            foreach ($apiCall['hydra:member'] as $call) {
                if (in_array($call['type'], $mitLizenz)) {
                    continue;
                }
                if ($call['type'] == 3) {
                    if (apply_filters($this->basename . '/is_theme_install', $call['slug'])) {
                        continue;
                    }
                    $child[] = $call;
                }
                if ($call['type'] == 4) {
                    if (apply_filters($this->basename . '/is_product_install', $call['slug'])) {
                        continue;
                    }
                    $pol[] = $call;
                }
                if ($call['type'] == 5) {
                    if (apply_filters($this->basename . '/is_theme_install', $call['slug'])) {
                        continue;
                    }
                    $tol[] = $call;
                }
            }
            $data = [
                'data' => [
                    'child' => $child,
                    'pol' => $pol,
                    'tol' => $tol
                ],
                'error' => $error

            ];
        }

        try {
            $template = $this->twig->render('@templates/api-call/product-api-call.html.twig', $data);
            $this->responseJson->template = $this->html_compress_template($template);
        } catch (LoaderError|SyntaxError|RuntimeError $e) {
            $this->responseJson->msg = $e->getMessage();
            return $this->responseJson;
        } catch (Throwable $e) {
            $this->responseJson->msg = $e->getMessage();
            return $this->responseJson;
        }
        $this->responseJson->status = true;
        return $this->responseJson;
    }

    private function free_product_download(): object
    {
        $this->responseJson->target = filter_input(INPUT_POST, 'target', FILTER_UNSAFE_RAW);

        $handle = filter_input(INPUT_POST, 'handle', FILTER_UNSAFE_RAW);
        $id = filter_input(INPUT_POST, 'id', FILTER_VALIDATE_INT);
        $body = [
            'product_id' => $id
        ];
        $fileInfo = apply_filters($this->basename . '/api_post_callback', 'download-free', json_encode($body), true);
        if (isset($fileInfo['error'])) {
            $this->responseJson->msg = $fileInfo['message'];
            return $this->responseJson;
        }
        $filePath = '';
        $install_dir = '';
        switch ($fileInfo['type']) {
            case '5':
                $install_dir = get_theme_root() . DIRECTORY_SEPARATOR;
                $filePath = $install_dir . $fileInfo['slug'] . '.zip';
                break;
            case '3':
                $pin = filter_input(INPUT_POST, 'pin', FILTER_VALIDATE_INT);
                //echo $this->main->get_oauth_save_pin();
                if ($pin != $this->main->get_oauth_save_pin()) {
                    $this->responseJson->msg = 'Falscher PIN!';
                    return $this->responseJson;
                }
                $install_dir = get_theme_root() . DIRECTORY_SEPARATOR;
                $filePath = $install_dir . $fileInfo['slug'] . '.zip';
                break;
            case'4':
                $install_dir = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR;
                $filePath = $install_dir . $fileInfo['slug'] . '.zip';
                break;
        }

        if (!$filePath) {
            $this->responseJson->msg = 'Download Fehler! - (Ajx ' . __LINE__ . ')';
            return $this->responseJson;
        }

        $zipFile = apply_filters($this->basename . '/product_download', $fileInfo['download']);
        @file_put_contents($filePath, $zipFile);
        WP_Filesystem();
        $unZipFile = unzip_file($filePath, $install_dir);
        if (!$unZipFile) {
            $this->responseJson->msg = 'Download fehlgeschlagen!';
            return $this->responseJson;
        }

        unlink($filePath);

        $this->responseJson->status = true;
        $this->responseJson->id = $id;
        $this->responseJson->handle = $handle;
        $this->responseJson->slug = $fileInfo['slug'];
        $this->responseJson->msg = 'Produkt erfolgreich installiert.';
        $this->responseJson->title = 'Download erfolgreich';
        return $this->responseJson;
    }

    private function product_activate(): object
    {

        $handle = filter_input(INPUT_POST, 'handle', FILTER_UNSAFE_RAW);
        $slug = filter_input(INPUT_POST, 'slug', FILTER_UNSAFE_RAW);
        if (!$handle || !$slug) {
            $this->responseJson->msg = 'aktivierung fehlgeschlagen! - (Ajx ' . __LINE__ . ')';
            return $this->responseJson;
        }
        $typeName = '';
        switch ($handle) {
            case 'pol':
                $plugin = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . $slug . DIRECTORY_SEPARATOR . $slug . '.php';
                $typeName = 'Plugin';
                $activate = activate_plugin($plugin);
                if (is_wp_error($activate)) {
                    $this->responseJson->msg = $activate->get_error_message();
                    return $this->responseJson;
                }
                break;
            case 'child':
            case 'tol':
                $typeName = 'Theme';

               // switch_theme($slug);
                break;
        }

        $this->responseJson->status = true;
        $this->responseJson->title = 'Aktivierung';
        $this->responseJson->msg = $typeName . ' erfolgreich aktiviert.';
        $this->responseJson->handle = $handle;
        return $this->responseJson;
    }

    private function download_lizenz_product():object
    {
        //api_get_callback
        $lizenz = filter_input(INPUT_POST, 'lizenz', FILTER_UNSAFE_RAW);
        if(!$lizenz){
            $this->responseJson->msg = 'Download fehlgeschlagen!';
            return $this->responseJson;
        }
        $download_uri =  $lizenz.'/token';

        apply_filters($this->basename.'/get_upload_token', $download_uri);
        return $this->responseJson;
    }

    private function activate_lizenz_product():object
    {
        $slug = filter_input(INPUT_POST, 'slug', FILTER_UNSAFE_RAW);
        $handle = filter_input(INPUT_POST, 'handle', FILTER_UNSAFE_RAW);
        $lizenz = filter_input(INPUT_POST, 'lizenz', FILTER_UNSAFE_RAW);
        $is_file = filter_input(INPUT_POST, 'is_file', FILTER_VALIDATE_INT);
        if(!$slug || !$handle || !$lizenz){
            $this->responseJson->msg = 'Aktivierung fehlgeschlagen! (Ajx - '.__LINE__.')';
            return $this->responseJson;
        }
        $activate_path = '';
        foreach (get_option($this->basename . '/lizenz_data') as $tmp) {
            if($tmp['product_license'] == $lizenz) {
                $activate_path = $tmp['config']['aktivierungs_file_path'];
                break;
            }
        }
        switch ($handle){
            case 'plugin':
                $plugin = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . $slug . DIRECTORY_SEPARATOR . $slug . '.php';
                if(!$is_file && $activate_path){
                    $file = apply_filters($this->basename . '/product_download', '/api/'.$lizenz.'/aktivierungs-file');
	                $response_code = wp_remote_retrieve_response_code( $file );
	                if($response_code !== 200){
		                $this->responseJson->msg = 'Aktivierung fehlgeschlagen! (ajx - '.__LINE__.')';
		                return $this->responseJson;
	                }
                    $dest = WP_PLUGIN_DIR .'/' . $slug . '/' . $activate_path;
                    @file_put_contents($dest, $file);
                }
                $activate = activate_plugin($plugin);
                if (is_wp_error($activate)) {
                    $this->responseJson->msg = $activate->get_error_message();
                    return $this->responseJson;
                }
                break;
            case'theme':
                if(!$is_file && $activate_path){
                    $file = apply_filters($this->basename . '/product_download', '/api/'.$lizenz.'/aktivierungs-file');
	                $response_code = wp_remote_retrieve_response_code( $file );
					if($response_code !== 200){
						$this->responseJson->msg = 'Aktivierung fehlgeschlagen! (ajx - '.__LINE__.')';
						return $this->responseJson;
					}
					$dest = get_theme_root().'/' . $slug . '/' . $activate_path;
                    @file_put_contents($dest, $file);
                }

                switch_theme($slug);
                break;
        }

        update_option($slug.'_product_install_authorize', 1);
        $this->responseJson->status = true;
        return $this->responseJson;

    }

    private function html_compress_template(string $string): string
    {
        if (!$string) {
            return $string;
        }
        return preg_replace(['/<!--(.*)-->/Uis', "/[[:blank:]]+/"], ['', ' '], str_replace(["\n", "\r", "\t"], '', $string));
    }
}