<?php
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Plugin uses custom tables and controlled internal query builders.
use SPAATG\ShortPixelLogger\ShortPixelLogger as Log;

use SPAATG\Model\SettingsModel as SettingsModel;

if ( ! defined( 'ABSPATH' ) ) {
 exit; // Exit if accessed directly.
}


/** Settings Model **/
class SPAATG_Settings extends \SPAATG\Model {
    const ACTIVATION_DATE_OPTION = 'spaatg_activation_date';
    const LEGACY_OPTION_PREFIX = 'wp' . '-spaatg-';
    const LEGACY_ACTIVATION_DATE_OPTION = 'activation-date';

    private $_apiKey = '';
    private $_verifiedKey = false;

    private static $_optionsMap = array(
        'apiKey' => array('key' => 'spaatg_apiKey', 'legacy' => 'apiKey', 'default' => '', 'group' => 'options'),
        'verifiedKey' => array('key' => 'spaatg_verifiedKey', 'legacy' => 'verifiedKey', 'default' => false, 'group' => 'options'),
        'siteAuthUser' => array('key' => 'spaatg_site-auth-user', 'legacy' => 'site-auth-user', 'default' => null, 'group' => 'options'),
        'siteAuthPass' => array('key' => 'spaatg_site-auth-pass', 'legacy' => 'site-auth-pass', 'default' => null, 'group' => 'options'),
        'currentVersion' => array('key' => 'spaatg_currentVersion', 'legacy' => 'currentVersion', 'default' => null, 'group' => 'options'),
        'currentStats' => array('key' => 'spaatg_current-total-files', 'legacy' => 'current-total-files', 'default' => null, 'group' => 'state'),
        'quotaExceeded' => array('key' => 'spaatg_quota-exceeded', 'legacy' => 'quota-exceeded', 'default' => 0, 'group' => 'state'),
        'httpProto' => array('key' => 'spaatg_protocol', 'legacy' => 'protocol', 'default' => 'https', 'group' => 'state'),
        'activationDate' => array('key' => self::ACTIVATION_DATE_OPTION, 'default' => null, 'group' => 'state'),
        'mediaLibraryViewMode' => array('key' => 'spaatg_view-mode', 'legacy' => 'view-mode', 'default' => false, 'group' => 'state'),
        'redirectedSettings' => array('key' => 'spaatg_redirected-settings', 'legacy' => 'redirected-settings', 'default' => null, 'group' => 'state'),
    );



    // This  array --  field_name -> (s)anitize mask
    protected $model = array(
        'apiKey' => array('s' => 'string'),
        'siteAuthUser' => array('s' => 'string'),
        'siteAuthPass' => array('s' => 'string'),
        'currentStats' => array('s' => 'array'),
    );

      public static function resetOptions() {
        foreach(self::$_optionsMap as $key => $val) {
            delete_option($val['key']);
            $legacyKey = self::getLegacyOptionKey($val);
            if (false !== $legacyKey) {
                delete_option($legacyKey);
            }
        }
        delete_option(self::legacyOption('bulk-previous-percent'));
    }

    public static function onActivate() {
        self::migrateLegacyOptions();
        update_option( self::ACTIVATION_DATE_OPTION, time(), 'no');

        $settingsModel = SettingsModel::getInstance();
				$updated = false;

				foreach(self::$_optionsMap as $option_name => $data)
				{
					 $value = self::getOpt($data['key'], $data['default']);
					 $bool = $settingsModel->setIfEmpty($option_name, $value);

					 // Remove setting if set, or if it doesn't exist in model anymore
					 if (true === $bool || false === $settingsModel->exists($option_name))
					 {
            //  Log::AddTrace('Would delete non-existing? setting ' . $option_name);
					//	  delete_option($data['key']);
					 		$updated = true;
					 }
				}


    }

    public static function onDeactivate() {

        delete_option(self::legacyOption('activation-notice'));
				delete_option(self::legacyOption('bulk-last-status')); // legacy shizzle
				delete_option(self::legacyOption('current-total-files'));
				delete_option(self::legacyOption('remove-settings-on-delete-plugin'));

				// Bulk State machine legacy
				$bulkLegacyOptions = array(
						self::legacyOption('bulk-type'),
						self::legacyOption('bulk-last-status'),
						self::legacyOption('query-id-start'),
						self::legacyOption('query-id-stop'),
						self::legacyOption('bulk-count'),
						self::legacyOption('bulk-previous-percent'),
						self::legacyOption('bulk-processed-items'),
						self::legacyOption('bulk-done-count'),
						self::legacyOption('last-bulk-start-time'),
						self::legacyOption('last-bulk-success-time'),
						self::legacyOption('bulk-running-time'),
						self::legacyOption('cancel-pointer'),
						self::legacyOption('skip-to-custom'),
						self::legacyOption('bulk-ever-ran'),
						self::legacyOption('flag-id'),
						self::legacyOption('failed-imgs'),
						'bulkProcessingStatus',
						self::legacyOption('prioritySkip'),
				);

				$removedStats = array(
						self::legacyOption('helpscout-optin'),
						self::legacyOption('activation-notice'),
						self::legacyOption('dismissed-notices'),
						self::legacyOption('media-alert'),
				);

				$removedOptions = array(
						self::legacyOption('remove-settings-on-delete-plugin'),
						self::legacyOption('custom-bulk-paused'),
						self::legacyOption('last-back-action'),
						self::legacyOption('front-bootstrap'),
				);

        // Settings completely removed during the settings redo
        $settingsRevamp = [
          self::legacyOption('front-bootstrap'),
					self::legacyOption('api-retries'),
					self::legacyOption('total-optimized'),
					self::legacyOption('total-original'),
					self::legacyOption('download-archive'),
					self::legacyOption('converted-png2jpg'),
          self::legacyOption('savedSpace'),
          self::legacyOption('fileCount'),
          self::legacyOption('files-under-5-percent'),
        ];

				$toRemove = array_merge($bulkLegacyOptions, $removedStats, $removedOptions, $settingsRevamp);

				foreach($toRemove as $option)
				{
					 delete_option($option);
				}
    }

    public function __get($name)
    {
        if (array_key_exists($name, self::$_optionsMap)) {
            return $this->getOpt(self::$_optionsMap[$name]['key'], self::$_optionsMap[$name]['default']);
        }
        // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace -- Magic getter notice keeps legacy access failures debuggable.
        $trace = debug_backtrace();
        // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error -- Magic getter notice keeps legacy access failures debuggable.
        trigger_error(
            'Undefined property via __get(): ' . esc_html($name) .
            ' in ' . esc_html($trace[0]['file']) .
            ' on line ' . esc_html($trace[0]['line']),
            E_USER_NOTICE);
        return null;
    }

    public function __set($name, $value) {
        if (array_key_exists($name, self::$_optionsMap)) {
            if($value !== null) {
                $this->setOpt(self::$_optionsMap[$name]['key'], $value);
            } else {
                delete_option(self::$_optionsMap[$name]['key']);
            }
        }
    }

		// Remove option. Only deletes with defined key!
		public function deleteOption($key)
		{
			  if(isset(self::$_optionsMap[$key]) && isset(self::$_optionsMap[$key]['key']))
				{
						$deleteKey = self::$_optionsMap[$key]['key'];
						delete_option($deleteKey);
				}
		}

    public static function getOpt($key, $default = null) {

				// This function required the internal Key. If this not given, but settings key, overwrite.
        if(isset(self::$_optionsMap[$key]['key'])) { //first try our name
						$default = self::$_optionsMap[$key]['default']; // first do default do to overwrite.
						$key = self::$_optionsMap[$key]['key'];
        }

        if ($key === self::ACTIVATION_DATE_OPTION) {
            self::migrateLegacyOptions();
        }

        $opt = get_option($key, $default);
				return $opt;
    }

    protected static function migrateLegacyOptions() {
        foreach (self::$_optionsMap as $data) {
            if (empty($data['key'])) {
                continue;
            }

            $new_value = get_option($data['key'], null);
            if ($new_value !== null && $new_value !== false) {
                continue;
            }

            $legacy_key = self::getLegacyOptionKey($data);
            if (false === $legacy_key) {
                continue;
            }

            $legacy_value = get_option($legacy_key, null);
            if ($legacy_value === null || $legacy_value === false) {
                continue;
            }

            update_option($data['key'], $legacy_value, 'no');
            delete_option($legacy_key);
        }

        $new_value = get_option(self::ACTIVATION_DATE_OPTION, null);
        if ($new_value !== null && $new_value !== false) {
            return;
        }

        $legacy_value = get_option(self::legacyOption(self::LEGACY_ACTIVATION_DATE_OPTION), null);
        if ($legacy_value === null || $legacy_value === false) {
            return;
        }

        update_option(self::ACTIVATION_DATE_OPTION, $legacy_value, 'no');
        delete_option(self::legacyOption(self::LEGACY_ACTIVATION_DATE_OPTION));
    }

    protected static function getLegacyOptionKey($data) {
        if (empty($data['legacy'])) {
            return false;
        }

        if (! empty($data['legacy_prefix'])) {
            return $data['legacy_prefix'] . $data['legacy'];
        }

        return self::legacyOption($data['legacy']);
    }

    protected static function legacyOption($suffix) {
        return self::LEGACY_OPTION_PREFIX . $suffix;
    }

    public function setOpt($key, $val) {
        $autoload = true;
        $ret = update_option($key, $val, $autoload);

        //hack for the situation when the option would just not update....
        if($ret === false && !is_array($val) && $val != get_option($key)) {
            delete_option($key);
            $alloptions = wp_load_alloptions();
            if ( isset( $alloptions[$key] ) ) {
                wp_cache_delete( 'alloptions', 'options' );
            } else {
                wp_cache_delete( $key, 'options' );
            }
            delete_option($key);
            add_option($key, $val, '', $autoload);

            // still not? try the DB way...
            if($ret === false && $val != get_option($key)) {
                global $wpdb;
	                $sql = "SELECT * FROM {$wpdb->prefix}options WHERE option_name = %s";
	                // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Query string contains a controlled WordPress options table name and is prepared before execution.
	                $sql = $wpdb->prepare( $sql, $key );
	                // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Query is prepared above; table name comes from $wpdb->prefix.
	                $rows = $wpdb->get_results($sql);
                if(count($rows) === 0) {
                    $wpdb->insert($wpdb->prefix.'options',
                                 array("option_name" => $key, "option_value" => (is_array($val) ? serialize($val) : $val), "autoload" => $autoload),
                                 array("option_name" => "%s", "option_value" => (is_numeric($val) ? "%d" : "%s")));
                } else { //update
	                    $option_value = maybe_serialize( $val );
	                    $sql = "update {$wpdb->prefix}options SET option_value = %s WHERE option_name = %s";
	                    // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Query string contains a controlled WordPress options table name and is prepared before execution.
	                    $sql = $wpdb->prepare( $sql, $option_value, $key );
	                    // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Query is prepared above; table name comes from $wpdb->prefix.
	                    $rows = $wpdb->get_results($sql);
                }

                if($val != get_option($key)) {
                    //tough luck, gonna use the bomb...
                    wp_cache_flush();
                    delete_option($key);
                    add_option($key, $val, '', $autoload);
                }
            }
        }
    }

} // class
