<?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 Sibs\Stargate\Config\SibsConfig;
use Sibs\Stargate\Constants\Logs;
use Sibs\Stargate\Constants\PaymentTypes;
use Sibs\Stargate\Constants\Plugin;
use Sibs\Stargate\Constants\WoocommerceOrderStatus;
use Sibs\Stargate\Loggers\SibsLogger;
use Sibs\Stargate\Utils\SibsVersion;

defined('ABSPATH') || exit;

/**
 * SIBS Activation Proccess.
 *
 * @param bool $network_wide
 */
function sibs_activation_process($network_wide)
{
    ob_start(); // Adicionar esta linha para iniciar o buffer
    create_sibs_tables($network_wide);

    $output = ob_get_clean();

    if (!empty($output)) {
        SibsLogger::warning('Unexpected output during activation: '.$output, Logs::INSTALL);
    }
}

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

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

/**
 * Create SIBS Tables.
 *
 * @param bool $network_wide
 */
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.
 */
function woocommerce_sibs_install_single_site()
{
    require_once constant('ABSPATH').'wp-admin/includes/upgrade.php';
    SibsVersion::fix_version_options();

    if (SibsVersion::need_to_migrate_db()) {
        SibsLogger::debug('Begin to Migrate Tables', Logs::INSTALL);
        woocommerce_sibs_install_migrations();
        SibsLogger::debug('End to Migrate Tables', Logs::INSTALL);

        SibsLogger::debug('Begin to Seed Tables', Logs::INSTALL);
        woocommerce_sibs_install_seeders();
        SibsLogger::debug('End to Seed Tables', Logs::INSTALL);

        SibsVersion::update_sibs_version();
        SibsVersion::sibs_default_language();
    }
}

/**
 * Woocommerce SIBS Install Migrations.
 */
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.
 */
function woocommerce_sibs_install_seeders()
{
    updatePluginWithVersionBefore_2_4_5();
    updatePluginWithVersionBefore_2_9_5();
}

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

    $general_option_name = SibsConfig::SIBS_GENERAL_CONFIG.'_%';
    $style_option_name = SibsConfig::SIBS_STYLE_CONFIG.'_%';
    $payment_option_name = 'woocommerce_'.Plugin::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, Logs::INSTALL);
    }
}

/**
 * Create SIBS Transaction Table.
 *
 * @param string $prefix
 * @param string $charset_collate
 */
function createSibsTransactionTable($prefix, $charset_collate)
{
    $pending_status = WoocommerceOrderStatus::PENDING;
    $tablePrefix = $prefix.Plugin::PLUGIN_PREFIX;
    $tableName = "{$tablePrefix}_transaction";

    SibsLogger::debug("Begin to create {$tableName} table", Logs::INSTALL);

    $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", Logs::INSTALL);
}

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

    SibsLogger::debug("Begin to create {$tableName} table", Logs::INSTALL);

    $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", Logs::INSTALL);
}

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

    SibsLogger::debug("Begin to create {$tableName} table", Logs::INSTALL);

    $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", Logs::INSTALL);
}

/**
 * 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
 */
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
 */
function updateSibsTransationTable($prefix)
{
    $tablePrefix = $prefix.Plugin::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
 */
function createSibsTokenizationTable($prefix, $charset_collate)
{
    SibsLogger::debug('Begin to create sibs tokenization table', Logs::INSTALL);

    $tablePrefix = $prefix.Plugin::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' => PaymentTypes::AUTH,
        'DB' => PaymentTypes::PURS,
    ];

    return $tmp[$name] ?? PaymentTypes::AUTH;
}

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

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

/**
 * Seed Function.
 */
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
 */
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 (null === $query_result) {
        $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
 */
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 (null === $query_result) {
        $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
 */
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 (null === $query_result) {
        $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
 */
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 (null === $query_result) {
        $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.
 */
function updatePluginWithVersionBefore_2_4_5()
{
    if (SibsVersion::need_to_seed_db('2.4.5')) {
        return;
    }

    SibsLogger::debug('Begin to Seed whith updatePluginWithVersionBefore_2_4_5', Logs::INSTALL);

    global $wpdb;
    $old_table_prefix = $wpdb->base_prefix.'sibs';
    $new_table_prefix = $wpdb->prefix.Plugin::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.
 */
function updatePluginWithVersionBefore_2_9_5()
{
    if (SibsVersion::need_to_seed_db('2.9.5')) {
        return;
    }

    SibsLogger::debug('Begin to Seed whith updatePluginWithVersionBefore_2_9_5', Logs::INSTALL);

    global $wpdb;
    $old_table_prefix = Plugin::PLUGIN_PREFIX;
    $new_table_prefix = $wpdb->prefix.Plugin::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');
}
