<?php

/**
 * Sibs Plugin Installation process.
 *
 * This file is used for creating tables while installing the plugins.
 * Copyright (c) SIBS
 *
 * @located at  /
 */
require_once __DIR__ . '/vendor/autoload.php';

use Sibs2\sibsConfig;
use Sibs2\sibsConstants;
use Sibs2\sibsLogger;
use Sibs2\sibsVersionController;

defined('ABSPATH') || exit;

/**
 * SIBS Activation Proccess.
 *
 * @param bool $network_wide
 * @return void
 */
function sibs_activation_process($network_wide)
{
    create_sibs_tables($network_wide);

    $output = ob_get_clean();

    if (! empty($output)) {
        sibsLogger::warning('Unexpected output during activation: ' . $output, sibsConstants::SIBS_INSTALL_LOG);
    }
}

/**
 * SIBS Deactivation Proccess.
 *
 * @return void
 */
function sibs_deactivation_process()
{
    // DO NOTHING
}

/**
 * SIBS Uninstallation Proccess.
 *
 * @return void
 */
function sibs_uninstallation_process()
{
    delete_sibs_options();
}

/**
 * Create SIBS Tables.
 *
 * @param bool $network_wide
 * @return void
 */
function create_sibs_tables($network_wide)
{
    global $wpdb;
    $wpdb->hide_errors();

    if ($network_wide) {
        $site_ids = (function_exists('get_sites') && function_exists('get_current_network_id')) ?
            get_sites(['fields' => 'ids', 'network_id' => get_current_network_id()]) :
            manually_get_sites();

        // Install the plugin for all these sites.
        foreach ($site_ids as $site_id) {
            switch_to_blog($site_id);
            woocommerce_sibs_install_single_site();
            restore_current_blog();
        }
    } else {
        woocommerce_sibs_install_single_site();
    }
}

/**
 * Manually Get Sites.
 *
 * @return mixed
 */
function manually_get_sites()
{
    global $wpdb;

    $query    = "SELECT `blog_id` FROM `{$wpdb->blogs}` WHERE `site_id` = %s;";
    $bindings = [$wpdb->siteid];

    return $wpdb->get_col(
        $wpdb->prepare($query, $bindings)
    );
}

/**
 * Woocommerce SIBS Install Single Site.
 *
 * @return void
 */
function woocommerce_sibs_install_single_site()
{
    require_once constant('ABSPATH') . 'wp-admin/includes/upgrade.php';
    sibsVersionController::fix_version_options();

    if (sibsVersionController::need_to_migrate_db()) {
        sibsLogger::debug('Begin to Migrate Tables', sibsConstants::SIBS_INSTALL_LOG);
        woocommerce_sibs_install_migrations();
        sibsLogger::debug('End to Migrate Tables', sibsConstants::SIBS_INSTALL_LOG);

        sibsLogger::debug('Begin to Seed Tables', sibsConstants::SIBS_INSTALL_LOG);
        woocommerce_sibs_install_seeders();
        sibsLogger::debug('End to Seed Tables', sibsConstants::SIBS_INSTALL_LOG);

        sibsVersionController::update_sibs_version();
        sibsVersionController::sibs_default_language();
    }
}

/**
 * Woocommerce SIBS Install Migrations.
 *
 * @return void
 */
function woocommerce_sibs_install_migrations()
{
    global $wpdb;
    $prefix          = $wpdb->prefix;
    $charset_collate = $wpdb->get_charset_collate();

    createSibsTransactionTable($prefix, $charset_collate);
    createSibsPaymentInformationTable($prefix, $charset_collate);
    createSibsTokenizationTable($prefix, $charset_collate);
    createSibsWebhookCallTable($prefix, $charset_collate);

    updateSibsTransationTable($prefix, $charset_collate);
}

/**
 * Woocommerce SIBS Install Seeders.
 *
 * @return void
 */
function woocommerce_sibs_install_seeders()
{
    updatePluginWithVersionBefore_2_4_5();
    updatePluginWithVersionBefore_2_9_5();
}

/**
 * Delete SIBS Options.
 *
 * @return void
 */
function delete_sibs_options()
{
    global $wpdb;

    $general_option_name = sibsConfig::SIBS_GENERAL_CONFIG . '_%';
    $style_option_name   = sibsConfig::SIBS_STYLE_CONFIG . '_%';
    $payment_option_name = 'woocommerce_' . sibsConstants::SIBS_PLUGIN_PREFIX . '%_settings';

    $delete_options_sql = "DELETE
        FROM `{$wpdb->options}`
        WHERE `option_name` LIKE '{$general_option_name}'
            OR `option_name` LIKE '{$style_option_name}'
            OR `option_name` LIKE '{$payment_option_name}'
    ";

    $wpdb->query($delete_options_sql);
}

/**
 * Log Create Table.
 */
function logCreateTable()
{
    global $wpdb;

    if ($wpdb->last_error) {
        sibsLogger::error('Create table error: ' . $wpdb->last_error, sibsConstants::SIBS_INSTALL_LOG);
    }
}

/**
 * Create SIBS Transaction Table.
 *
 * @param string $prefix
 * @param string $charset_collate
 * @return void
 */
function createSibsTransactionTable($prefix, $charset_collate)
{
    $pending_status  = sibsConstants::WOOCOMMERCE_ORDER_STATUS_PENDING;
    $tablePrefix     = $prefix . sibsConstants::SIBS_PLUGIN_PREFIX;
    $tableName       = "{$tablePrefix}_transaction";

    sibsLogger::debug("Begin to create $tableName table", sibsConstants::SIBS_INSTALL_LOG);

    $transaction_sql = "CREATE TABLE IF NOT EXISTS `{$tableName}` (
        `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
        `customer_id` BIGINT(20) UNSIGNED DEFAULT NULL,
        `order_no` BIGINT(20) UNSIGNED NOT NULL,
        `reference_id` VARCHAR(32) NOT NULL,
        `captured_id` VARCHAR(100) NULL,
        `refunded_id` VARCHAR(100) NULL,
        `payment_id` VARCHAR(100) NOT NULL,
        `payment_type` VARCHAR(50) NOT NULL,
        `payment_brand` VARCHAR(100) NOT NULL,
        `payment_status` VARCHAR(30) NOT NULL DEFAULT '{$pending_status}',
        `date` DATETIME NOT NULL,
        `currency` CHAR(3) NOT NULL,
        `amount` DECIMAL(17,2) NOT NULL,
        `additional_information` LONGTEXT NULL,
        `refund_status` VARCHAR(100) NULL,
        `refunded_amount` DECIMAL(17,2) NOT NULL DEFAULT '0',
        `refund_information` LONGTEXT NULL,
        `capture_status` VARCHAR(100) NULL,
        `captured_amount` DECIMAL(17,2) NOT NULL DEFAULT '0',
        `capture_information` LONGTEXT NULL,
        `active` TINYINT(1) UNSIGNED NOT NULL DEFAULT '1',
        PRIMARY KEY (`id`),
        UNIQUE KEY (`order_no`),
        UNIQUE KEY (`reference_id`),
        UNIQUE KEY (`captured_id`),
        UNIQUE KEY (`refunded_id`),
        KEY (`customer_id`)
    ) $charset_collate;";

    dbDelta($transaction_sql);

    logCreateTable();

    sibsLogger::debug("End to create $tableName table", sibsConstants::SIBS_INSTALL_LOG);
}

/**
 * Create SIBS Payment Information Table.
 *
 * @param string $prefix
 * @param string $charset_collate
 * @return void
 */
function createSibsPaymentInformationTable($prefix, $charset_collate)
{
    $tablePrefix = $prefix . sibsConstants::SIBS_PLUGIN_PREFIX;
    $tableName   = "{$tablePrefix}_payment_information";

    sibsLogger::debug("Begin to create $tableName table", sibsConstants::SIBS_INSTALL_LOG);

    $payment_information_sql = "CREATE TABLE IF NOT EXISTS `{$tableName}` (
        `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
        `cust_id` BIGINT(20) NOT NULL,
        `reg_id` VARCHAR(32),
        `payment_group` VARCHAR(6),
        `brand` VARCHAR(100),
        `holder` VARCHAR(100) NULL DEFAULT NULL,
        `email` VARCHAR(100) NULL DEFAULT NULL,
        `last4digits` VARCHAR(4),
        `expiry_month` VARCHAR(2),
        `expiry_year` VARCHAR(4),
        `server_mode` VARCHAR(4) NOT NULL,
        `channel_id` VARCHAR(32) NOT NULL,
        `payment_default` BOOLEAN NOT NULL DEFAULT '0',
        PRIMARY KEY (`id`),
        UNIQUE KEY(`cust_id`, `last4digits`, `expiry_month`, `expiry_year`)
    ) $charset_collate;";

    dbDelta($payment_information_sql);

    logCreateTable();

    sibsLogger::debug("End to create $tableName table", sibsConstants::SIBS_INSTALL_LOG);
}

/**
 * Create SIBS Webhook Call Table.
 *
 * @param string $prefix
 * @param string $charset_collate
 * @return void
 */
function createSibsWebhookCallTable($prefix, $charset_collate)
{
    $tablePrefix = $prefix . sibsConstants::SIBS_PLUGIN_PREFIX;
    $tableName   = "{$tablePrefix}_webhook_retry";

    sibsLogger::debug("Begin to create $tableName table", sibsConstants::SIBS_INSTALL_LOG);

    $webhook_call_sql = "CREATE TABLE IF NOT EXISTS `$tableName` (
        `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
        `notification_id` VARCHAR(127),
        `url` VARCHAR(255) NOT NULL,
        `headers` TEXT,
        `payload` TEXT,
        `decoded_payload` TEXT,
        `exception` TEXT,
        `arrived` INT DEFAULT 1,
        `processed_qty` INT DEFAULT 0,
        `processed_at` DATETIME,
        `created_at` TIMESTAMP NOT NULL DEFAULT NOW(),
        PRIMARY KEY (`id`),
        UNIQUE KEY(`notification_id`)
    ) $charset_collate;";

    dbDelta($webhook_call_sql);

    logCreateTable();

    sibsLogger::debug("End to create $tableName table", sibsConstants::SIBS_INSTALL_LOG);
}

/**
 * Check Col Exist.
 *
 * @param string $tableName
 * @param string $colName
 * @return bool
 */
function checkColExist($tableName, $colName)
{
    global $wpdb;

    $col_result = $wpdb->get_results(
        "SELECT `COLUMN_NAME`
        FROM `INFORMATION_SCHEMA`.`COLUMNS`
        WHERE `table_name` = '$tableName'
        AND `COLUMN_NAME` = '$colName';",
        ARRAY_A
    );

    return ! empty($col_result);
}

/**
 * Add Col To Table.
 *
 * @param string $tableName
 * @param string $colName
 * @param string $colType
 * @param string $colDefault
 * @param string $colAfter
 * @return void
 */
function addColToTable($tableName, $colName, $colType = 'LONGTEXT', $colDefault = null, $colAfter = null)
{
    global $wpdb;

    $col_query = "ALTER TABLE `{$tableName}` ADD `$colName` $colType";

    if (! empty($colDefault)) {
        $col_query .= " DEFAULT $colDefault"; // If is string it has to be like '"string"'
    }

    if (! empty($colAfter)) {
        $col_query .= " AFTER `$colAfter`";
    }

    $col_query .= ';';

    $wpdb->query($col_query);
}

/**
 * Update SIBS Transaction Table.
 *
 * @param string $prefix
 * @return void
 */
function updateSibsTransationTable($prefix)
{
    $tablePrefix        = $prefix . sibsConstants::SIBS_PLUGIN_PREFIX;
    $tableName          = "{$tablePrefix}_transaction";

    $is_formConfig_col  = checkColExist($tableName, 'formConfig');

    if (empty($is_formConfig_col)) {
        addColToTable($tableName, 'formConfig', 'LONGTEXT', 'NULL', 'payment_status');
    }

    $is_formContext_col = checkColExist($tableName, 'formContext');

    if (empty($is_formContext_col)) {
        addColToTable($tableName, 'formContext', 'LONGTEXT', 'NULL', 'formConfig');
    }

    $is_signature_col   = checkColExist($tableName, 'signature');

    if (empty($is_signature_col)) {
        addColToTable($tableName, 'signature', 'LONGTEXT', 'NULL', 'formContext');
    }

    $is_spg_style_col   = checkColExist($tableName, 'spg_style');

    if (empty($is_spg_style_col)) {
        addColToTable($tableName, 'spg_style', 'LONGTEXT', 'NULL', 'signature');
    }
}

/**
 * Create SIBS Tokenization Table.
 *
 * @param string $prefix
 * @param string $charset_collate
 * @return void
 */
function createSibsTokenizationTable($prefix, $charset_collate)
{
    sibsLogger::debug('Begin to create sibs tokenization table', sibsConstants::SIBS_INSTALL_LOG);

    $tablePrefix      = $prefix . sibsConstants::SIBS_PLUGIN_PREFIX;
    $tokenization_sql = "CREATE TABLE IF NOT EXISTS `{$tablePrefix}_card_tokens` (
        `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
        `id_customer` BIGINT(20) UNSIGNED NOT NULL,
        `token_name` VARCHAR(100) NOT NULL,
        `token_type` VARCHAR(32) NOT NULL,
        `value` VARCHAR(100) NOT NULL,
        `masked_pan` VARCHAR(32) NOT NULL,
        `expire_date` VARCHAR(32) NOT NULL,
        `expire_date_example` VARCHAR(6) NOT NULL,
        PRIMARY KEY (`id`),
        UNIQUE KEY(`value`)
    ) $charset_collate;";

    dbDelta($tokenization_sql);
}

/**
 * Migrate Payment Type.
 *
 * @param string $name
 * @return string
 */
function migrate_payment_type($name)
{
    $tmp = [
        'PA' => sibsConstants::SPG_PAYMENT_TYPE_AUTH,
        'DB' => sibsConstants::SPG_PAYMENT_TYPE_PURS,
    ];

    return $tmp[$name] ?? sibsConstants::SPG_PAYMENT_TYPE_AUTH;
}

/**
 * Migrate Payment Status.
 *
 * @param string $status
 * @param string $type
 * @return string
 */
function migrate_payment_status($status, $type)
{
    $tmp = ($type == 'PA') ? [
        'wc-sibs-processing'  => sibsConstants::SIBS_ORDER_STATUS_AUTHORIZED,
        'wc-payment-accepted' => sibsConstants::SIBS_ORDER_STATUS_AUTHORIZED,
        'wc-payment-captured' => sibsConstants::WOOCOMMERCE_ORDER_STATUS_PROCESSING,
    ] : [
        'wc-sibs-processing'  => sibsConstants::WOOCOMMERCE_ORDER_STATUS_PROCESSING,
        'wc-payment-accepted' => sibsConstants::WOOCOMMERCE_ORDER_STATUS_PROCESSING,
        'wc-payment-captured' => sibsConstants::WOOCOMMERCE_ORDER_STATUS_PROCESSING,
    ];

    return $tmp[$status] ?? $status;
}

/**
 * Seed Function.
 *
 * @param string $old_table_name
 * @param string $new_table_name
 * @param callable $seedFunction
 * @return void
 */
function seedFunction(string $old_table_name, string $new_table_name, callable $seedFunction)
{
    global $wpdb;
    $query = $wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($old_table_name));

    if ($wpdb->get_var($query) == $old_table_name) {
        $query          = "SELECT * FROM `$old_table_name`";
        $results        = $wpdb->get_results($query, ARRAY_A);
        foreach ($results as $result) {
            call_user_func($seedFunction, $new_table_name, $result);
        }
    }
}

/**
 * Seed Transaction Table.
 *
 * @param string $table_name
 * @param mixed $result
 * @return void
 */
function seedTransactionTable($table_name, $result)
{
    global $wpdb;

    $result_no     = $result['order_no'];
    $query         = "SELECT * FROM `$table_name` WHERE `order_no` = %s";
    $query_prepare = $wpdb->prepare($query, $result_no);
    $query_result  = $wpdb->get_row($query_prepare, ARRAY_A);

    if ($query_result === null) {
        $data        = [
            'order_no'                => $result_no,
            'customer_id'             => $result['customer_id'],
            'reference_id'            => $result['reference_id'],
            'captured_id'             => $result['captured_id'] ?? null,
            'refunded_id'             => $result['refunded_id'] ?? null,
            'payment_id'              => str_replace('sibs_', 'sibs_stg_', $result['payment_id']),
            'payment_type'            => migrate_payment_type($result['payment_type']), //PA => AUTH   DB => PURS
            'payment_brand'           => $result['payment_brand'],
            'payment_status'          => migrate_payment_status($result['payment_status'], $result['payment_type']),
            'date'                    => $result['date'],
            'currency'                => $result['currency'],
            'amount'                  => $result['amount'],
            'additional_information'  => $result['additional_information'],
            'capture_status'          => $result['capture_status'] ?? null,
            'captured_amount'         => $result['captured_amount'] ?? 0.00,
            'capture_information'     => $result['capture_information'] ?? null,
            'refund_status'           => $result['refund_status'],
            'refunded_amount'         => $result['refunded_amount'],
            'refund_information'      => $result['refund_information'],
        ];
        $dataFormat = ['%d', '%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'];

        $wpdb->insert(
            $table_name,
            $data,
            $dataFormat
        );
    }
}

/**
 * Seed Payment InFormtion Table.
 *
 * @param string $table_name
 * @param mixed $result
 * @return void
 */
function seedPaymentInformationTable($table_name, $result)
{
    global $wpdb;

    $cust_id       = $result['cust_id'];
    $query         = "SELECT * FROM `$table_name` WHERE `cust_id` = %s";
    $query_prepare = $wpdb->prepare($query, $cust_id);
    $query_result  = $wpdb->get_row($query_prepare, ARRAY_A);

    if ($query_result === null) {
        $data        = [
            'cust_id'         => $result['cust_id'],
            'payment_group'   => $result['payment_group'],
            'brand'           => $result['brand'],
            'holder'          => $result['holder'],
            'email'           => $result['email'],
            'last4digits'     => $result['last4digits'],
            'expiry_month'    => $result['expiry_month'],
            'expiry_year'     => $result['expiry_year'],
            'server_mode'     => $result['server_mode'],
            'channel_id'      => $result['channel_id'],
            'reg_id'          => $result['reg_id'],
            'payment_default' => $result['payment_default'],
        ];
        $dataFormat = ['%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d'];

        $wpdb->insert(
            $table_name,
            $data,
            $dataFormat
        );
    }
}

/**
 * Seed Card Token Table.
 *
 * @param string $table_name
 * @param mixed $result
 * @return void
 */
function seedCardTokenTable($table_name, $result)
{
    global $wpdb;

    $result_no     = $result['value'];
    $query         = "SELECT * FROM `$table_name` WHERE `value` = %s";
    $query_prepare = $wpdb->prepare($query, $result_no);
    $query_result  = $wpdb->get_row($query_prepare, ARRAY_A);

    if ($query_result === null) {
        $data        = [
            'id_customer'         => $result['id_customer'],
            'token_name'          => $result['token_name'],
            'token_type'          => $result['token_type'],
            'value'               => $result_no,
            'masked_pan'          => $result['masked_pan'],
            'expire_date'         => $result['expire_date'],
            'expire_date_example' => $result['expire_date_example'],
        ];
        $dataFormat = ['%d', '%s', '%s', '%s', '%s', '%s', '%s'];

        $wpdb->insert(
            $table_name,
            $data,
            $dataFormat
        );
    }
}

/**
 * Seed Webhook Call Table.
 *
 * @param string $table_name
 * @param mixed $result
 * @return void
 */
function seedWebhookCallTable($table_name, $result)
{
    global $wpdb;

    $result_no     = $result['notification_id'];
    $query         = "SELECT * FROM `$table_name` WHERE `notification_id` = %s";
    $query_prepare = $wpdb->prepare($query, $result_no);
    $query_result  = $wpdb->get_row($query_prepare, ARRAY_A);

    if ($query_result === null) {
        $data        = [
            'notification_id' => $result_no,
            'url'             => $result['url'],
            'headers'         => $result['headers'],
            'payload'         => $result['payload'],
            'decoded_payload' => $result['decoded_payload'],
            'exception'       => $result['exception'],
            'arrived'         => $result['arrived'],
            'processed_qty'   => $result['processed_qty'],
            'processed_at'    => $result['processed_at'],
            'created_at'      => $result['created_at'],
        ];
        $dataFormat = ['%s', '%s', '%s', '%s', '%s', '%s', '%d', '%d', '%s', '%s'];

        $wpdb->insert(
            $table_name,
            $data,
            $dataFormat
        );
    }
}

/**
 * Update Plugin With Version Before 2.4.5.
 *
 * @return void
 */
function updatePluginWithVersionBefore_2_4_5()
{
    if (sibsVersionController::need_to_seed_db('2.4.5')) {
        return;
    }

    sibsLogger::debug('Begin to Seed whith updatePluginWithVersionBefore_2_4_5', sibsConstants::SIBS_INSTALL_LOG);

    global $wpdb;
    $old_table_prefix = $wpdb->base_prefix . 'sibs';
    $new_table_prefix = $wpdb->prefix . sibsConstants::SIBS_PLUGIN_PREFIX;

    // Seed wp_sibs_transaction ----------> wp_sibs_stg_transaction
    $old_table_name = "{$old_table_prefix}_transaction";
    $new_table_name = "{$new_table_prefix}_transaction";
    seedFunction($old_table_name, $new_table_name, 'seedTransactionTable');

    // Seed wp_sibs_payment_information --> wp_sibs_stg_payment_information
    $old_table_name   = "{$old_table_prefix}_payment_information";
    $new_table_name   = "{$new_table_prefix}_payment_information";

    seedFunction($old_table_name, $new_table_name, 'seedPaymentInformationTable');
}

/**
 * Update Plugin With Version Before 2.9.5.
 *
 * @return void
 */
function updatePluginWithVersionBefore_2_9_5()
{
    if (sibsVersionController::need_to_seed_db('2.9.5')) {
        return;
    }

    sibsLogger::debug('Begin to Seed whith updatePluginWithVersionBefore_2_9_5', sibsConstants::SIBS_INSTALL_LOG);

    global $wpdb;
    $old_table_prefix = sibsConstants::SIBS_PLUGIN_PREFIX;
    $new_table_prefix = $wpdb->prefix . sibsConstants::SIBS_PLUGIN_PREFIX;

    // Seed sibs_stg_payment_information --> wp_sibs_stg_payment_information
    $old_table_name = "{$old_table_prefix}_payment_information";
    $new_table_name = "{$new_table_prefix}_payment_information";
    seedFunction($old_table_name, $new_table_name, 'seedPaymentInformationTable');

    // Seed sibs_stg_card_tokens ----------> wp_sibs_stg_card_tokens
    $old_table_name = "{$old_table_prefix}_card_tokens";
    $new_table_name = "{$new_table_prefix}_card_tokens";
    seedFunction($old_table_name, $new_table_name, 'seedCardTokenTable');

    // Seed sibs_stg_webhook_calls --------> wp_sibs_stg_webhook_retry
    $old_table_name = "{$old_table_prefix}_webhook_calls";
    $new_table_name = "{$new_table_prefix}_webhook_retry";
    seedFunction($old_table_name, $new_table_name, 'seedWebhookCallTable');

    // Seed wp_sibs_stg_webhook_calls -----> wp_sibs_stg_webhook_retry
    $old_table_name = "{$new_table_prefix}_webhook_calls"; // Yes: This is using new table prefix
    $new_table_name = "{$new_table_prefix}_webhook_retry";
    seedFunction($old_table_name, $new_table_name, 'seedWebhookCallTable');
}
