<?php

namespace GriffinForms\Frontend\Ajax;

use GriffinForms\Includes\Payments\CartBuilder;
use GriffinForms\Includes\Payments\GatewayServiceResolver;

class Payments extends \GriffinForms\Frontend\Format
{
    /**
     * AJAX nonce action.
     *
     * @var string
     */
    protected $nonce_action = 'griffinforms_payment_flow';

    /**
     * Submission SQL helper.
     *
     * @var \GriffinForms\Frontend\Sql\Submission
     */
    protected $submission_sql;

    protected function setSubmissionsql(): void
    {
        $this->submission_sql = \GriffinForms\Frontend\Sql\Submission::getInstance();
    }

    public function __construct()
    {
        add_action('wp_ajax_griffinforms_create_payment_intent', [$this, 'createPaymentIntent']);
        add_action('wp_ajax_nopriv_griffinforms_create_payment_intent', [$this, 'createPaymentIntent']);

        add_action('wp_ajax_griffinforms_resume_payment_intent', [$this, 'resumePaymentIntent']);
        add_action('wp_ajax_nopriv_griffinforms_resume_payment_intent', [$this, 'resumePaymentIntent']);

        add_action('wp_ajax_griffinforms_complete_payment', [$this, 'completePayment']);
        add_action('wp_ajax_nopriv_griffinforms_complete_payment', [$this, 'completePayment']);

        $this->setAll();
    }

    /**
     * Initialize or reuse a payment intent.
     */
    public function createPaymentIntent()
    {
        $this->enforceNonce();

        $form_id = absint($_POST['form_id'] ?? 0);
        $submission_id = absint($_POST['submission_id'] ?? 0);
        $token = sanitize_text_field($_POST['submission_token'] ?? '');
        $gateway = sanitize_key($_POST['gateway'] ?? '');

        if (!$form_id || !$submission_id || '' === $token) {
            wp_send_json_error(['message' => __('Invalid payment request.', 'griffinforms-form-builder')], 400);
        }
        $gateway = $this->resolveGatewayRequest($submission_id, $gateway, 'init');

        $submission = $this->loadSubmissionRow($submission_id, $token, $form_id);
        if (!$submission) {
            wp_send_json_error(['message' => __('Submission could not be located for payment.', 'griffinforms-form-builder')], 404);
        }

        $cart = $this->buildSubmissionCart($form_id, $submission);

        if (empty($cart['items'])) {
            if (method_exists($this->log, 'add')) {
                $this->log->add(
                    'error',
                    'payment',
                    $submission_id,
                    get_current_user_id(),
                    'Payment cart empty when creating intent. Raw payload type: ' . gettype($submission['submission'] ?? null),
                    'payment'
                );
            }
            wp_send_json_error(['message' => __('No products selected for payment.', 'griffinforms-form-builder')], 400);
        }

        $hashes = \GriffinForms\Includes\Payments\CartHasher::getInstance()->compute($cart, $gateway);

        $gateway_service = $this->resolveGatewayService($gateway);
        $result = $gateway_service->createSession([
            'form_id'        => $form_id,
            'submission_id'  => $submission_id,
            'cart'           => $cart,
            'cart_hash'      => $hashes['cart_hash'],
            'amount_hash'    => $hashes['amount_hash'],
            'gateway'        => $gateway,
            'field_values'   => $cart['field_values'],
            'field_types'    => $cart['field_types'],
        ]);

        if (is_wp_error($result)) {
            wp_send_json_error(['message' => $result->get_error_message()], 400);
        }

        wp_send_json_success($result);
    }

    /**
     * Fetch an existing intent/client secret.
     */
    public function resumePaymentIntent()
    {
        $this->enforceNonce();

        $form_id = absint($_POST['form_id'] ?? 0);
        $submission_id = absint($_POST['submission_id'] ?? 0);
        $token = sanitize_text_field($_POST['submission_token'] ?? '');
        $gateway = sanitize_key($_POST['gateway'] ?? '');

        if (!$form_id || !$submission_id || '' === $token) {
            wp_send_json_error(['message' => __('Invalid payment request.', 'griffinforms-form-builder')], 400);
        }
        $gateway = $this->resolveGatewayRequest($submission_id, $gateway, 'resume');

        $submission = $this->loadSubmissionRow($submission_id, $token, $form_id);
        if (!$submission) {
            wp_send_json_error(['message' => __('Submission could not be located for payment.', 'griffinforms-form-builder')], 404);
        }

        $cart = $this->buildSubmissionCart($form_id, $submission);
        $hashes = \GriffinForms\Includes\Payments\CartHasher::getInstance()->compute($cart, $gateway);

        $gateway_service = $this->resolveGatewayService($gateway);
        $result = $gateway_service->resumeSession($submission_id, $hashes['cart_hash'], $hashes['amount_hash'], $cart);

        if (is_wp_error($result)) {
            wp_send_json_error(['message' => $result->get_error_message()], 400);
        }

        wp_send_json_success($result);
    }

    /**
     * Mark submission as paid/failed after confirmation.
     */
    public function completePayment()
    {
        $this->enforceNonce();

        $form_id = absint($_POST['form_id'] ?? 0);
        $submission_id = absint($_POST['submission_id'] ?? 0);
        $token = sanitize_text_field($_POST['submission_token'] ?? '');
        $gateway = sanitize_key($_POST['gateway'] ?? '');
        $payload = $this->getCompletionPayload();

        if (!$form_id || !$submission_id || '' === $token || empty($payload)) {
            wp_send_json_error(['message' => __('Invalid payment completion request.', 'griffinforms-form-builder')], 400);
        }
        $gateway = $this->resolveGatewayRequest($submission_id, $gateway, 'complete');

        $submission = $this->loadSubmissionRow($submission_id, $token, $form_id);
        if (!$submission) {
            wp_send_json_error(['message' => __('Submission could not be located for payment.', 'griffinforms-form-builder')], 404);
        }

        $gateway_service = $this->resolveGatewayService($gateway);
        $result = $gateway_service->completeSession($submission_id, $payload);

        if (is_wp_error($result)) {
            wp_send_json_error(['message' => $result->get_error_message()], 400);
        }

        wp_send_json_success(['status' => 'completed']);
    }

    /**
     * Verify nonce token.
     */
    protected function enforceNonce(): void
    {
        $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
        if (!wp_verify_nonce($nonce, $this->nonce_action)) {
            wp_send_json_error(['message' => __('Security check failed.', 'griffinforms-form-builder')], 403);
        }
    }

    /**
     * Fetch submission row ensuring ownership.
     */
    protected function loadSubmissionRow(int $submission_id, string $token, int $form_id): ?array
    {
        $table = $this->config->getTable('submission');
        global $wpdb;
        $row = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM %i WHERE id = %d AND public_token = %s",
                $table,
                $submission_id,
                $token
            ),
            ARRAY_A
        );

        if (!$row || (int) ($row['form_id'] ?? 0) !== $form_id) {
            return null;
        }

        return $row;
    }

    /**
     * Build the authoritative cart from stored submission payload.
     */
    protected function buildSubmissionCart(int $form_id, array $submission): array
    {
        $cart_builder = CartBuilder::getInstance();
        $payload_raw = $submission['submission'] ?? [];
        $payload = maybe_unserialize($payload_raw);
        if (!is_array($payload)) {
            $decoded = json_decode(wp_unslash($payload_raw), true);
            if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
                $payload = $decoded;
            }
        }

        return $cart_builder->build($form_id, is_array($payload) ? $payload : []);
    }

    /**
     * Resolve the gateway against active configuration.
     */
    protected function resolveGatewayRequest(int $submission_id, string $gateway, string $operation): string
    {
        $payment_registry = \GriffinForms\Includes\Integrations\Categories\Payment::getInstance();
        $allowed_gateways = array_values(array_filter(array_map('sanitize_key', $payment_registry->getAllowedProviderIds())));
        $configured_gateways = array_keys($payment_registry->getConfiguredProviders());
        $available_gateways = array_values(array_intersect($allowed_gateways, $configured_gateways));
        if (empty($available_gateways)) {
            $this->log->add(
                'error',
                'submission',
                $submission_id,
                get_current_user_id(),
                sprintf('Payment %s blocked: no active payment gateway configured.', $operation),
                'Payment Integration (pending)'
            );
            wp_send_json_error(['message' => __('Payments are currently disabled by the site administrator.', 'griffinforms-form-builder')], 400);
        }

        if ($gateway === '') {
            $gateway = $available_gateways[0];
        }

        if (!in_array($gateway, $available_gateways, true)) {
            $log_gateway = $available_gateways[0] ?? $gateway;
            $this->log->add(
                'error',
                'submission',
                $submission_id,
                get_current_user_id(),
                sprintf('Payment %s blocked: requested gateway "%s" is not currently enabled/configured.', $operation, $gateway),
                sprintf('Payment Integration (%s)', $log_gateway)
            );
            wp_send_json_error(['message' => __('Selected payment gateway is not available.', 'griffinforms-form-builder')], 400);
        }

        return $gateway;
    }

    /**
     * Resolve the runtime service implementation for the gateway.
     */
    protected function resolveGatewayService(string $gateway)
    {
        $resolver = GatewayServiceResolver::getInstance();
        $service = $resolver->getService($gateway);
        if (!$service) {
            wp_send_json_error(['message' => __('Selected payment gateway is not supported yet.', 'griffinforms-form-builder')], 400);
        }

        return $service;
    }

    /**
     * Build a generic completion payload for gateway services.
     */
    protected function getCompletionPayload(): array
    {
        $payload = array();

        if (isset($_POST['intent_id'])) {
            $payload['intent_id'] = sanitize_text_field(wp_unslash($_POST['intent_id']));
        }
        if (isset($_POST['order_id'])) {
            $payload['order_id'] = sanitize_text_field(wp_unslash($_POST['order_id']));
        }
        if (isset($_POST['payment_data'])) {
            $raw = wp_unslash($_POST['payment_data']);
            if (is_string($raw) && $raw !== '') {
                $decoded = json_decode($raw, true);
                if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
                    $payload = array_merge($payload, $decoded);
                }
            } elseif (is_array($raw)) {
                foreach ($raw as $key => $value) {
                    $payload[sanitize_key((string) $key)] = is_scalar($value) ? sanitize_text_field((string) $value) : $value;
                }
            }
        }

        return $payload;
    }
}
