<?php
/**
 * Pay4All Form variant of the TWINT SOAP engine's ConfigProvider.
 *
 * The base ConfigProvider (Engine\Adapter\ConfigProvider) is hard-coded to a
 * shop order via WpBridge::get_wc_order(): for Form orders that would return false and
 * crash. This subclass:
 *
 *   - Resolves a p4all_order through FormOrderShim.
 *   - Overrides every getter that touches WC-only methods (get_total,
 *     get_currency, get_formatted_amount, billing helpers, URL builders…).
 *   - Routes the SOAP webhook callbacks to home_url('/?p4all_form_pay=…')
 *     so FormWebhookHandler picks them up instead of the WC checkout pipeline.
 *
 * All meta read/write keeps going through OrderDataRepository, whose
 * resolve_order_for_meta filter we already wired in FormIntegration.
 */

namespace Twnt4All\Pay4All;

use Twnt4All\Checkout\OrderDataRepository;
use Twnt4All\Engine\Adapter\ConfigProvider;

if ( ! defined( 'ABSPATH' ) ) { exit; }

class FormConfigProvider extends ConfigProvider
{
    /** @var FormOrderShim|null */
    protected $shim;

    public function set_order( $order_id )
    {
        $this->order_id = $order_id;
        $this->shim     = FormOrderRegistry::get_or_load( (int) $order_id );

        if ( $this->shim ) {
            FormOrderRegistry::register( $this->shim );
        }

        // The parent reads $this->order in several spots. Point it at the shim
        // so inherited methods that we don't override still see a coherent
        // object instead of null.
        $this->order = $this->shim;

        return $this;
    }

    public function get_currency()
    {
        return $this->shim ? strtoupper( $this->shim->get_currency() ) : 'CHF';
    }

    public function get_total()
    {
        $total = $this->shim ? (float) $this->shim->get_total() : 0.0;
        return function_exists( 'wc_format_decimal' )
            ? wc_format_decimal( $total, 2 )
            : number_format( $total, 2, '.', '' );
    }

    public function get_formatted_amount()
    {
        $total = $this->shim ? (float) $this->shim->get_total() : 0.0;
        return number_format( $total, 2, '.', '' );
    }

    public function get_or_create_merchant_reference( $reversal = false )
    {
        $saved = $this->shim ? (string) $this->shim->get_meta( '_p4all_twint_reference', true ) : '';
        if ( $saved !== '' ) {
            $ref = mb_substr( $saved, 0, 50, 'utf-8' );
            if ( $reversal ) {
                $ref = mb_substr( $ref, 0, 35, 'utf-8' );
                $ref .= '_' . uniqid();
            }
            return $ref;
        }

        $ref = $this->shim ? $this->shim->get_order_number() : (string) $this->order_id;

        $first = $this->shim ? $this->shim->get_billing_first_name() : '';
        $last  = $this->shim ? $this->shim->get_billing_last_name()  : '';
        if ( $first !== '' ) { $ref .= '_' . $first; }
        if ( $last  !== '' ) { $ref .= '_' . $last;  }

        if ( function_exists( 'iconv' ) ) {
            $ref = @iconv( 'UTF-8', 'ASCII//TRANSLIT', $ref );
        }
        $ref = preg_replace( '/[^\s\w-]/u', '', (string) $ref );
        $ref = mb_substr( $ref, 0, 35, 'utf-8' );
        $ref .= '_' . uniqid();

        if ( $this->shim ) {
            $this->shim->update_meta_data( '_p4all_twint_reference', $ref );
            $this->shim->save();
        }
        return $ref;
    }

    public function is_order_started()
    {
        if ( ! $this->shim ) { return false; }
        if ( (bool) $this->shim->get_meta( '_p4all_twint_order_started', true ) ) {
            return true;
        }
        $this->shim->update_meta_data( '_p4all_twint_order_started', true );
        $this->shim->save();
        return false;
    }

    public function is_order_complete( $cache = false )
    {
        if ( ! $this->shim ) { return false; }
        $payment = (array) get_post_meta( $this->order_id, '_p4all_payment', true );
        return ( $payment[ 'status' ] ?? '' ) === 'paid';
    }

    public function get_order_received_url()
    {
        return $this->shim ? $this->shim->get_checkout_order_received_url() : home_url( '/' );
    }

    public function get_checkout_url()
    {
        return $this->shim ? $this->shim->get_checkout_payment_url() : home_url( '/' );
    }

    public function get_checkout_payment_url()
    {
        return $this->shim ? $this->shim->get_checkout_payment_url() : home_url( '/' );
    }

    public function get_cancel_order_url()
    {
        return $this->shim ? $this->shim->get_cancel_order_url() : home_url( '/' );
    }

    public function get_timeout_url()
    {
        return $this->get_checkout_payment_url();
    }

    public function get_failure_url()
    {
        return $this->get_checkout_payment_url();
    }

    // -----------------------------------------------------------------
    // SOAP webhook callbacks — must point to FormWebhookHandler endpoints,
    // not to the shop's api_request_url helper. Mirrors FormWalletRequest URL
    // shape so the existing handler picks them up without any change.
    // -----------------------------------------------------------------

    public function get_webhook_redirect_url( $args = [] )
    {
        $args = array_merge( [
            FormWebhookHandler::QUERY_VAR => 'redirect',
            'order_id'                   => (int) $this->order_id,
            'order_number'               => $this->shim ? $this->shim->get_order_number() : '',
            'uuid'                       => $this->get_order_uuid(),
            's'                          => $this->build_signature(),
        ], $args );

        return add_query_arg( $args, home_url( '/' ) );
    }

    public function get_webhook_cancel_url( $args = [] )
    {
        $args = array_merge( [
            FormWebhookHandler::QUERY_VAR => 'cancel',
            'order_id'                   => (int) $this->order_id,
            'order_number'               => $this->shim ? $this->shim->get_order_number() : '',
            'uuid'                       => $this->get_order_uuid(),
            's'                          => $this->build_signature(),
        ], $args );

        return add_query_arg( $args, home_url( '/' ) );
    }

    public function get_webhook_order_update_notification_url()
    {
        return add_query_arg( [
            FormWebhookHandler::QUERY_VAR => 'webhook',
            'order_id'                   => (int) $this->order_id,
            'order_number'               => $this->shim ? $this->shim->get_order_number() : '',
            'r'                          => OrderDataRepository::get_order_data( $this->shim, 'reference' ),
        ], home_url( '/' ) );
    }

    /**
     * Reproduces the WalletPaymentHandler::get_redirect_key() signature scheme
     * so FormWebhookHandler::verify_signature() (already wired in Pay4All Pro)
     * can validate the `s` parameter on the callback without changes.
     */
    private function build_signature() : string
    {
        if ( ! $this->shim ) { return ''; }
        $data = [
            'order_id'           => $this->shim->get_id(),
            'amount'             => $this->shim->get_total(),
            'currency'           => $this->shim->get_currency(),
            'billing_first_name' => $this->shim->get_billing_first_name(),
            'billing_last_name'  => $this->shim->get_billing_last_name(),
            'billing_postcode'   => $this->shim->get_billing_postcode(),
            'integration'        => 'twnt',
        ];
        // Signature carries a real timestamp so the return URL is not
        // replayable indefinitely (the previous fixed « 1 » made the
        // signature time-independent). Verify_signature() re-derives the
        // hash from the embedded timestamp and rejects it past the
        // T4A_REDIRECT_SIGNATURE_EXPIRATION window.
        return (string) \Twnt4All\Support\WpBridge::create_hash_key( http_build_query( $data, '', ';' ), time() );
    }
}
