<?php

namespace Twnt4All\Checkout;

use Twnt4All\Support\Journal;
use Twnt4All\Support\WooBridge;
use Twnt4All\Support\WpBridge;

/**
 * Class OrderDataRepository
 * @package Twnt4All\gateway
 */
class OrderDataRepository
{
    /**
     * Returns the TWINT order data either completely as an array or only one property if $index is defined.
     *
     * @param mixed $order Order object, WC_Order when WC is present, or Form order id.
     * @param null $index
     * @param bool $cache
     * @return mixed
     */
    public static function get_order_data( $order, $index = null )
    {
        // Route Form orders (and any other duck-typed order id) through the
        // shim before WooBridge falls back to wc_get_order. Same filter that
        // save_order_data / delete_order_data already use, so the read and
        // write paths now treat Form orders consistently.
        if ( ! is_object( $order ) ) {
            $order = self::resolve_order_for_meta( $order );
        }

        $order_data = WooBridge::get_order_meta( $order, '_t4a_twint_order' );

        if ( $index === null ) {
            return $order_data;
        }

        if ( $order_data && isset( $order_data[ $index ] ) ) {
            return $order_data[ $index ];
        }

        // Legacy support.
        return WooBridge::get_order_meta( $order, 'twint_' . $index );
    }

    /**
     * Saves the TWINT order data. Only saves data which are not empty.
     *
     * @param $order_id
     * @param array $args
     */
    public static function save_order_data( $order_id, $args )
    {
        $order      = self::resolve_order_for_meta( $order_id );
        $order_data = WooBridge::get_order_meta( $order, '_t4a_twint_order' );

        if ( !$order_data ) {
            $order_data = array();
        }

        foreach ( $args as $k => $v ) {
            if ( $v ) {
                $order_data[ $k ] = $v;
            }
        }

        WooBridge::update_order_meta( $order, '_t4a_twint_order', $order_data );
    }

    /**
     * Deletes all TWINT order data in array $args.
     *
     * @param $order_id
     * @param array $args
     */
    public static function delete_order_data( $order_id, $args )
    {
        $order      = self::resolve_order_for_meta( $order_id );
        $order_data = WooBridge::get_order_meta( $order, '_t4a_twint_order' );

        if ( !$order_data ) {
            return;
        }

        foreach ( $args as $k ) {
            $order_data[ $k ] = null;
            unset( $order_data[ $k ] );
        }

        // Don't dump $args : even though these are field names (not values),
        // they enumerate the payment-related metadata the plugin stores and
        // fall under the reviewer's blanket policy on SOAP-adjacent data.
        Journal::event( sprintf( 'Deleted %d order-data field(s)', is_array( $args ) ? count( $args ) : 0 ) );

        WooBridge::update_order_meta( $order, '_t4a_twint_order', $order_data );
    }

    /**
     * Saves a TWINT transaction in the array of transactions
     *
     * @param $order_id
     * @param $data
     */
    public static function save_transaction( $order_id, $data )
    {
        // Guard: WC order helpers live in pay4all-pro.
        if ( ! class_exists( '\\Twnt4All\\Support\\WooBridge' ) ) { return; }
        $order = WpBridge::get_wc_order( $order_id );
        if ( ! $order ) { return; }
        $transactions = WooBridge::get_order_meta( $order, '_t4a_twint_transactions' );

        if ( !$transactions ) {
            $transactions = array();
        }

        $data           = array_intersect_key( $data, [ 'operation' => '', 'reference' => '', 'amount' => '', 'fee' => '' ] );
        $transactions[] = $data;

        WooBridge::update_order_meta( $order, '_t4a_twint_transactions', $transactions );
        // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- T4A_PREFIX equals the plugin's internal prefix (`t4a_twint`) ; the sniffer cannot statically resolve the concatenation.
        do_action( T4A_PREFIX . '_save_transaction', $order, $data, $transactions );
    }

    public static function update_transactions( $order, $transactions )
    {
        if ( is_string( $order ) || is_numeric( $order ) ) {
            // Guard: WC order helpers live in pay4all-pro.
            $order = WpBridge::get_wc_order( $order );
        }
        if ( ! class_exists( '\\Twnt4All\\Support\\WooBridge' ) ) { return false; }

        if ( !$order ) {
            return false;
        }

        WooBridge::update_order_meta( $order, '_t4a_twint_transactions', $transactions );
        // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound -- T4A_PREFIX equals the plugin's internal prefix (`t4a_twint`) ; the sniffer cannot statically resolve the concatenation.
        do_action( T4A_PREFIX . '_update_transactions', $order, $transactions );

        return true;
    }

    /**
     * Returns the TWINT transactions.
     *
     * @param mixed $order_id Order id or order object.
     * @return mixed
     */
    public static function get_transactions( $order_id )
    {
        return WooBridge::get_order_meta( $order_id, '_t4a_twint_transactions' );
    }

    /**
     * Returns the merchant reference or creates a new one if no merchant reference is available.
     * Always creates a new reference for reversals.
     *
     * @param $order_id
     * @param bool $reversal
     * @return bool|string
     */
    public static function get_merchant_reference( $order_id )
    {
        return static::get_order_data( $order_id, 'reference' );
    }

    public static function clean_post_meta_cache( $post_id )
    {
        wp_cache_delete( $post_id, 'post_meta' );
    }

    public static function get_integration()
    {
        return 'direct';
    }

    public static function get_payment_type()
    {
        return get_option( 't4a_twint_settings_payment_type', 'immediate' );
    }

    /**
     * Resolve an order id to an "order-like" object for meta read/write.
     *
     * The default behaviour is unchanged: WpBridge::get_wc_order( $order_id ) for
     * any WC order. Other integrations (currently Pay4All Form via FormOrderRegistry)
     * can short-circuit by returning a duck-typed object through the
     * `p4all_pro_resolve_order_for_meta` filter. Returning anything truthy
     * skips the WC lookup entirely; returning null/false falls through to WC.
     *
     * This is the single fork between the WC checkout path and the Pay4All
     * Form path. Keeping it here (instead of in two callers) means the rest
     * of the repository — save_transaction, update_transactions, the multi-site
     * lookup helpers — stays untouched.
     *
     * @param int|string $order_id
     * @return mixed WooCommerce order (when WC present) or duck-typed object, or false.
     */
    protected static function resolve_order_for_meta( $order_id )
    {
        // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- historical Pay4All Pro filter name kept for backwards compatibility with existing integrations (Pay4All Shop and downstream).
        $custom = apply_filters( 'p4all_pro_resolve_order_for_meta', null, $order_id );
        if ( $custom ) { return $custom; }
        // Guard: WC order lookup lives in pay4all-pro. WpBridge helper returns null when WC absent.
        $order = WpBridge::get_wc_order( $order_id );
        return $order ?: false;
    }
}