<?php

use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry;
use Automattic\WooCommerce\Utilities\FeaturesUtil;

/*
 * Plugin Name:          Stitch Express
 * Description:          Use Stitch Express to easily and securely accept Card payment on your WooCommerce store.
 * Plugin URI:           https://wordpress.org/plugins/stitchexpress/
 * Version:              1.7.0
 * Requires at least:    6.5
 * Requires PHP:         8.0
 * WC requires at least: 8.0
 * WC tested up to:      10.5
 * Author:               Stitch Express
 * Author URI:           https://express.stitch.money
 * License:              GPL v3
 * License URI:          https://www.gnu.org/licenses/gpl-3.0.html
 * Text Domain:          stitch-express
 */

defined('ABSPATH') || exit;

define('STITCH_EXPRESS_PLUGIN_URL', untrailingslashit(plugins_url(basename(plugin_dir_path(__FILE__)), basename(__FILE__))));
define('STITCH_EXPRESS_PLUGIN_PATH', untrailingslashit(plugin_dir_path(__FILE__)));

// One-time migration: disable widget for existing installs where it was incorrectly enabled by default.
add_action('plugins_loaded', 'stitch_express_migrate_widget_default', 10);
function stitch_express_migrate_widget_default(): void {
    if (get_option('stitch_express_widget_default_migrated')) {
        return;
    }

    $settings = get_option('woocommerce_stitch-express_settings');

    if (is_array($settings) && ($settings['widget_enabled'] ?? '') === 'yes') {
        $settings['widget_enabled'] = 'no';
        update_option('woocommerce_stitch-express_settings', $settings);
    }

    update_option('stitch_express_widget_default_migrated', '1');
}

add_action('plugins_loaded', 'stitch_express_init_gateway', 11);
function stitch_express_init_gateway(): void {
    if (!class_exists('WC_Payment_Gateway')) {
        // WooCommerce is not defined
        return;
    }

    if (class_exists('Stitch_Express_Payment_Gateway')) {
        // Already initialised
        return;
    }

    require_once STITCH_EXPRESS_PLUGIN_PATH.'/includes/stitch-express-gateway.php';

    require_once STITCH_EXPRESS_PLUGIN_PATH.'/includes/stitch-express-product-widget.php';

    // Initialize product widget with error handling
    try {
        new Stitch_Express_Product_Widget();
    } catch (Throwable $e) {
        // Log error but don't break the plugin (catches both Exception and Error)
        error_log('Stitch Express: Failed to initialize product widget - '.$e->getMessage());
    }
}

add_filter('plugin_action_links_'.plugin_basename(__FILE__), 'stitch_express_plugin_admin_links');
function stitch_express_plugin_admin_links(array $links): array {
    $link = '<a href="'.admin_url('admin.php?page=wc-settings&tab=checkout&section=stitch-express').'">'.__('Settings', 'stitch-express').'</a>';
    array_unshift($links, $link);

    return $links;
}

add_filter('woocommerce_payment_gateways', 'stitch_express_add_gateway');
function stitch_express_add_gateway(array $methods): array {
    $methods[] = 'Stitch_Express_Payment_Gateway';

    return $methods;
}

// Auto-update opt-in notice.
add_action('admin_notices', 'stitch_express_auto_update_notice');
add_action('admin_post_stitch_express_enable_auto_updates', 'stitch_express_handle_enable_auto_updates');
add_action('admin_post_stitch_express_dismiss_auto_update_notice', 'stitch_express_handle_dismiss_auto_update_notice');

function stitch_express_auto_update_notice(): void {
    $screen = get_current_screen();
    if (!$screen || !in_array($screen->id, ['plugins', 'woocommerce_page_wc-settings'], true)) {
        return;
    }

    if (!current_user_can('update_plugins')) {
        return;
    }

    $plugin_file = plugin_basename(__FILE__);
    $auto_updates = (array) get_site_option('auto_update_plugins', []);

    if (in_array($plugin_file, $auto_updates, true)) {
        return;
    }

    if (get_option('stitch_express_auto_update_dismissed')) {
        return;
    }

    $enable_url = wp_nonce_url(
        admin_url('admin-post.php?action=stitch_express_enable_auto_updates'),
        'stitch_express_auto_update'
    );
    $dismiss_url = wp_nonce_url(
        admin_url('admin-post.php?action=stitch_express_dismiss_auto_update_notice'),
        'stitch_express_auto_update'
    );
    ?>
    <div class="notice" style="
        background: linear-gradient(135deg, #FFF7ED 0%, #FFFBF5 100%);
        border: 1px solid #F59E0B;
        border-left: 4px solid #F59E0B;
        border-radius: 6px;
        padding: 16px 20px;
        margin: 15px 0;
        display: flex;
        align-items: flex-start;
        gap: 14px;
        max-width: 800px;
    ">
        <div style="flex: 1;">
            <p style="margin: 0 0 6px; font-weight: 600; font-size: 14px; color: #92400E;">
                Stitch Express &mdash; Enable Auto-Updates
            </p>
            <p style="margin: 0 0 12px; color: #78350F; font-size: 13px; line-height: 1.5;">
                Auto-updates are not enabled for Stitch Express. We recommend enabling them so your store
                receives critical security and payment fixes as soon as they are released.
            </p>
            <div style="display: flex; gap: 8px; align-items: center;">
                <a href="<?php echo esc_url($enable_url); ?>" class="button button-primary">Enable Auto-Updates</a>
                <a href="<?php echo esc_url($dismiss_url); ?>" class="button">Dismiss</a>
            </div>
        </div>
    </div>
    <?php
}

function stitch_express_handle_enable_auto_updates(): void {
    if (!current_user_can('update_plugins')) {
        wp_die(__('You do not have permission to manage plugin updates.', 'stitch-express'));
    }
    check_admin_referer('stitch_express_auto_update');

    $plugin_file = plugin_basename(STITCH_EXPRESS_PLUGIN_PATH.'/stitch-express.php');
    $auto_updates = (array) get_site_option('auto_update_plugins', []);

    if (!in_array($plugin_file, $auto_updates, true)) {
        $auto_updates[] = $plugin_file;
        update_site_option('auto_update_plugins', $auto_updates);
    }

    wp_safe_redirect(wp_get_referer() ?: admin_url('plugins.php'));

    exit;
}

function stitch_express_handle_dismiss_auto_update_notice(): void {
    if (!current_user_can('update_plugins')) {
        wp_die(__('You do not have permission to manage plugin updates.', 'stitch-express'));
    }
    check_admin_referer('stitch_express_auto_update');

    update_option('stitch_express_auto_update_dismissed', '1', false);

    wp_safe_redirect(wp_get_referer() ?: admin_url('plugins.php'));

    exit;
}

add_action('rest_api_init', 'stitch_express_register_rest_api_routes');
function stitch_express_register_rest_api_routes(): void {
    register_rest_route(
        'stitch-express/v1',
        '/callback',
        [
            'methods' => 'GET',
            'callback' => 'stitch_express_handle_callback',
            'permission_callback' => '__return_true',
        ]
    );

    register_rest_route(
        'stitch-express/v1',
        '/webhook',
        [
            'methods' => 'POST',
            'callback' => 'stitch_express_handle_webhook',
            'permission_callback' => '__return_true',
        ]
    );
}

function stitch_express_complete_order_payment(WC_Order $order, string $payment_id, string $reference, string $source, Stitch_Express_Client $client, bool $override = false): bool {
    $logger = wc_get_logger();
    $can_complete = in_array($order->get_status(), ['awaiting-payment', 'pending', 'cancelled', 'failed'], true);

    if (!$can_complete && !$override) {
        $logger->info(
            "{$source}: Order {$order->get_id()} status is '{$order->get_status()}', skipping payment completion.",
            ['source' => 'stitch-express']
        );

        return false;
    }

    if (in_array($order->get_status(), ['cancelled', 'failed'], true)) {
        $order->add_order_note(
            sprintf(
                'Stitch Express: Payment confirmed (ID: %s) while order was "%s". Order status will be updated.',
                $payment_id,
                $order->get_status()
            )
        );
    }

    $previous_status = $order->get_status();

    $order->payment_complete($payment_id);
    $order->save();

    $logger->info(
        "{$source}: Payment completed for order {$order->get_id()}. Order status updated from '{$previous_status}' to '{$order->get_status()}'. Stitch Payment ID: {$payment_id}",
        ['source' => 'stitch-express']
    );

    try {
        $client->confirm_delivery($payment_id, $reference);
    } catch (Exception $e) {
        $logger->error(
            "{$source}: Failed to send delivery confirmation for payment {$payment_id}: {$e->getMessage()}",
            ['source' => 'stitch-express']
        );
    }

    return true;
}

/**
 * GET callback handler — used for user browser redirects.
 */
function stitch_express_handle_callback(WP_REST_Request $request): WP_REST_Response {
    $gateway = new Stitch_Express_Payment_Gateway();
    $logger = wc_get_logger();

    $reference = $request->get_param('reference');
    $payment_id = $request->get_param('payment_id');
    $split_string = explode('-', $reference);
    $order_id = $split_string[1];
    $override = $request->get_param('override') === 'true';

    $order = wc_get_order($order_id);

    if (!$order) {
        $logger->error("Order not found for ID: {$order_id}", ['source' => ' stitch-express']);
        wc_add_notice('Order not found', 'error');

        return stitch_express_generate_redirect_response(home_url());
    }

    $stitch_express_client = new Stitch_Express_Client($gateway->get_option('client_id'), $gateway->get_option('client_secret'));

    try {
        $payment_status = $stitch_express_client->get_payment_status($payment_id, $reference);
    } catch (Exception $exception) {
        $logger->error($exception, ['source' => 'stitch-express']);
        wc_add_notice('Failed to check status of your payment. Please contact the store.', 'error');

        return stitch_express_generate_redirect_response($order->get_view_order_url());
    }

    if ($payment_status === null) {
        $logger->error("Payment link not found for payment ID: {$payment_id} and reference: {$reference}", ['source' => 'stitch-express']);
        wc_add_notice('Payment not found', 'error');

        return stitch_express_generate_redirect_response($order->get_view_order_url());
    }

    if ($payment_status !== 'PAID') {
        $logger->warning("Unpaid status ({$payment_status}) for payment {$payment_id}", ['source' => 'stitch-express']);
        wc_add_notice('Payment not completed', 'error');

        return stitch_express_generate_redirect_response($order->get_view_order_url());
    }

    stitch_express_complete_order_payment($order, $payment_id, $reference, 'Callback', $stitch_express_client, $override);

    return stitch_express_generate_redirect_response($order->get_checkout_order_received_url());
}

/**
 * POST webhook handler — used for server-to-server confirmation from Express.
 */
function stitch_express_handle_webhook(WP_REST_Request $request): WP_REST_Response {
    $gateway = new Stitch_Express_Payment_Gateway();
    $logger = wc_get_logger();
    $client_secret = $gateway->get_option('client_secret');

    // Verify HMAC signature
    $signature = $request->get_header('x_stitch_express_signature');
    $raw_body = $request->get_body();

    if (!$signature || !$client_secret) {
        $logger->error('Webhook received without signature or client secret not configured', ['source' => 'stitch-express']);

        return new WP_REST_Response(['success' => false, 'error' => 'Unauthorized'], 401);
    }

    $hashed_secret = base64_encode(hash('sha256', $client_secret, true));
    $expected_signature = hash_hmac('sha256', $raw_body, $hashed_secret);

    if (!hash_equals($expected_signature, $signature)) {
        $logger->error('Webhook HMAC signature verification failed', ['source' => 'stitch-express']);

        return new WP_REST_Response(['success' => false, 'error' => 'Invalid signature'], 401);
    }

    // Parse JSON body
    $body = json_decode($raw_body, true);

    if (!$body || !isset($body['payment_id']) || !isset($body['reference'])) {
        $logger->error('Webhook received with invalid body', ['source' => 'stitch-express']);

        return new WP_REST_Response(['success' => false, 'error' => 'Invalid request body'], 400);
    }

    $payment_id = $body['payment_id'];
    $reference = $body['reference'];
    $split_string = explode('-', $reference);

    if (count($split_string) < 2) {
        $logger->error("Webhook received with invalid reference format: {$reference}", ['source' => 'stitch-express']);

        return new WP_REST_Response(['success' => false, 'error' => 'Invalid reference format'], 400);
    }

    $order_id = $split_string[1];
    $order = wc_get_order($order_id);

    if (!$order) {
        $logger->error("Webhook: Order not found for ID: {$order_id}", ['source' => 'stitch-express']);

        return new WP_REST_Response(['success' => false, 'error' => 'Order not found'], 404);
    }

    $stitch_express_client = new Stitch_Express_Client($gateway->get_option('client_id'), $gateway->get_option('client_secret'));

    try {
        $payment_status = $stitch_express_client->get_payment_status($payment_id, $reference);
    } catch (Exception $exception) {
        $logger->error("Webhook: Failed to check payment status - {$exception->getMessage()}", ['source' => 'stitch-express']);

        return new WP_REST_Response([
            'success' => false,
            'error' => 'Failed to check payment status',
            'order_id' => (string) $order_id,
            'order_status' => $order->get_status(),
        ], 500);
    }

    if ($payment_status === null) {
        $logger->error("Webhook: Payment link not found for payment ID: {$payment_id} and reference: {$reference}", ['source' => 'stitch-express']);

        return new WP_REST_Response([
            'success' => false,
            'error' => 'Payment not found',
            'order_id' => (string) $order_id,
            'order_status' => $order->get_status(),
        ], 404);
    }

    if ($payment_status !== 'PAID') {
        $logger->warning("Webhook: Unpaid status ({$payment_status}) for payment {$payment_id}", ['source' => 'stitch-express']);

        return new WP_REST_Response([
            'success' => false,
            'error' => "Payment not completed (status: {$payment_status})",
            'order_id' => (string) $order_id,
            'order_status' => $order->get_status(),
        ], 422);
    }

    stitch_express_complete_order_payment($order, $payment_id, $reference, 'Webhook', $stitch_express_client);

    return new WP_REST_Response([
        'success' => true,
        'order_id' => (string) $order_id,
        'order_status' => $order->get_status(),
    ], 200);
}

function stitch_express_generate_redirect_response(string $url): WP_REST_Response {
    return new WP_REST_Response(
        null,
        302,
        [
            'Location' => $url,
        ]
    );
}

add_action('wp_enqueue_scripts', 'stitch_express_enqueue_checkout_styles');
function stitch_express_enqueue_checkout_styles() {
    if (is_checkout()) {
        wp_enqueue_style(
            'stitch-express-classic-checkout-style',
            STITCH_EXPRESS_PLUGIN_URL.'/assets/classic-checkout.css',
            [],
            filemtime(STITCH_EXPRESS_PLUGIN_PATH.'/build/index.css')
        );
    }
}

add_action('woocommerce_blocks_loaded', 'stitch_express_load_gateway_block_support');
function stitch_express_load_gateway_block_support(): void {
    if (!class_exists('Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType')) {
        return;
    }

    require_once STITCH_EXPRESS_PLUGIN_PATH.'/includes/stitch-express-block.php';
    add_action(
        'woocommerce_blocks_payment_method_type_registration',
        static function (PaymentMethodRegistry $payment_method_registry) {
            $container = Package::container();
            // registers as shared instance.
            $container->register(
                Stitch_Express_Blocks_Support::class,
                static function () {
                    return new Stitch_Express_Blocks_Support();
                }
            );
            $payment_method_registry->register(
                $container->get(Stitch_Express_Blocks_Support::class)
            );
        },
    );
}

add_action('before_woocommerce_init', static function () {
    if (!class_exists('\Automattic\WooCommerce\Utilities\FeaturesUtil')) {
        return;
    }

    FeaturesUtil::declare_compatibility('cart_checkout_blocks', __FILE__, true);
    FeaturesUtil::declare_compatibility('custom_order_tables', __FILE__, true);
});
