<?php

namespace CleantalkSP\SpbctWP\Scanner\DBTrigger;

final class DBTriggerService
{
    private static $option_name = 'spbc_db_triggers';

    /**
     * Set found triggers to storage.
     * @param array $bad_triggers
     *
     * @return void
     */
    final public static function saveTriggersStorage($bad_triggers)
    {
        if (is_array($bad_triggers)) {
            $scanned_triggers = self::loadTriggersStorage();
            $scanned_triggers = array_merge($scanned_triggers, $bad_triggers);
            update_option(self::$option_name, $scanned_triggers);
        }
    }

    /**
     * Get found triggers from storage.
     * @return array
     */
    final public static function loadTriggersStorage()
    {
        $triggers = get_option(self::$option_name, []);
        return is_array($triggers) ? $triggers : [];
    }

    /**
     * Get count of triggers from storage.
     * @return int
     */
    final public static function countTriggersStorage()
    {
        return count(self::loadTriggersStorage());
    }

    /**
     * Get all triggers exists in the database schema.
     *
     * @return array The list of triggers.
     */
    final public static function getDataBaseTriggers()
    {
        global $wpdb;
        $db_triggers = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT TRIGGER_NAME, EVENT_MANIPULATION, EVENT_OBJECT_TABLE, ACTION_STATEMENT, ACTION_TIMING 
                FROM information_schema.TRIGGERS 
                WHERE TRIGGER_SCHEMA = %s",
                $wpdb->dbname
            )
        );

        return is_array($db_triggers) ? $db_triggers : array();
    }

    /**
     * Get cloud signatures for triggers from local database.
     * @return array
     */
    final public static function getSignaturesForTriggers()
    {
        global $wpdb;
        $cloud_signatures = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT id, name, body FROM " . SPBC_TBL_SCAN_SIGNATURES . " WHERE type = %s",
                'TRIGGER'
            ),
            ARRAY_N
        );
        if (!is_array($cloud_signatures)) {
            $cloud_signatures = array();
        }
        foreach ($cloud_signatures as $key => $signature) {
            $cloud_signatures[$signature[0]] = [$signature[1], $signature[2]];
            unset($cloud_signatures[$key]);
        }
        return $cloud_signatures;
    }

    /**
     * Delete trigger from storage.
     * @param string $trigger_name
     * @return bool
     */
    final public static function deleteTrigger($trigger_name)
    {
        global $wpdb;

        // @psalm-suppress WpdbUnsafeMethodsIssue
        $wpdb->query('DROP TRIGGER IF EXISTS ' . $trigger_name);

        $triggers = self::loadTriggersStorage();
        $triggers = array_filter($triggers, function ($trigger) use ($trigger_name) {
            return $trigger['name'] !== $trigger_name;
        });
        return update_option(self::$option_name, $triggers);
    }

    /**
     * Remove triggers that are not in the database schema, but are in the storage.
     * @return void
     */
    final public static function removeNotExistsTriggers()
    {
        $db_triggers = self::getDataBaseTriggers();
        $scanned_triggers = self::loadTriggersStorage();

        $scanned_triggers_names = array_column($scanned_triggers, 'name');
        $db_triggers_names = array_column($db_triggers, 'TRIGGER_NAME');
        $not_exists_triggers = array_diff($scanned_triggers_names, $db_triggers_names);

        // Update storage with remaining triggers
        if (!empty($not_exists_triggers)) {
            $updated_triggers = array_filter($scanned_triggers, function ($trigger) use ($not_exists_triggers) {
                return !in_array($trigger['name'], $not_exists_triggers);
            });
            update_option(self::$option_name, $updated_triggers);
        }
    }
}
