<?php
if (!defined('ABSPATH')) exit;

/**
 * Free Escrow baseline (manual admin credit)
 *
 * Storage choice:
 *  - Use order postmeta to store escrow records for auction orders.
 *
 * Justification:
 *  - Lightweight and reversible: no new DB tables required for the free baseline.
 *  - Keeps escrow "existence" in the free plugin while extensions can later implement
 *    a separate table or enhanced storage if desired.
 *  - We use the order ID as the escrow identifier (unique, easy to query).
 *
 * Escrow meta keys (stored on the order post):
 *  - _stakmv_escrow_status     (pending|approved|refunded)
 *  - _stakmv_escrow_vendor     (vendor user ID)
 *  - _stakmv_escrow_amount     (float)
 *  - _stakmv_escrow_created_at (datetime)
 *  - _stakmv_escrow_approved_by
 *  - _stakmv_escrow_approved_at
 *
 * Lifecycle hooks (free exposes these; extensions may auto-approve later):
 *  - do_action('stakmv_escrow_created', $escrow_id, $data)
 *  - do_action('stakmv_escrow_approved', $escrow_id, $data)
 *  - do_action('stakmv_escrow_refunded', $escrow_id, $data)
 *
 * Important: On manual approval we will trigger do_action('stakmv_wallet_credit', ...)
 * rather than performing any direct balance changes. Extensions may listen for the
 * stakmv_wallet_credit action to perform ledger writes.
 */

/**
 * Create an escrow record for an order if it relates to an auction.
 * Returns true if created, false if nothing done.
 */
function stakmv_create_escrow_for_order($order_id) {
    if (!$order_id) {
        return false;
    }

    $order = wc_get_order($order_id);
    if (!$order) {
        return false;
    }

    // Only handle auction-related orders
    $auction_id = $order->get_meta('_stakmv_auction_id');
    if (!$auction_id) {
        return false;
    }

    // Avoid creating duplicate escrow records
    if (get_post_meta($order_id, '_stakmv_escrow_status', true)) {
        return false;
    }

    $vendor_id = (int) get_post_field('post_author', $auction_id);
    if ($vendor_id <= 0) {
        return false;
    }

    $amount = (float) $order->get_total();

    update_post_meta($order_id, '_stakmv_escrow_status', 'pending');
    update_post_meta($order_id, '_stakmv_escrow_vendor', $vendor_id);
    update_post_meta($order_id, '_stakmv_escrow_amount', $amount);
    update_post_meta($order_id, '_stakmv_escrow_created_at', current_time('mysql'));

    $data = [
        'vendor_id'  => $vendor_id,
        'amount'     => $amount,
        'auction_id' => $auction_id,
        'order_id'   => $order_id,
    ];

    /**
     * Escrow created: free plugin notifies extensions.
     * $escrow_id is the order ID for the free baseline.
     */
    do_action('stakmv_escrow_created', $order_id, $data);

    return true;
}

/**
 * Calculate commission/net payout for a gross amount.
 *
 * @param float $amount Gross order amount.
 * @return array{rate:float, commission:float, net:float}
 */
function stakmv_calculate_commission_split($amount) {
    $amount = (float) $amount;
    $rate = (float) stakmv_get_option('commission_rate', 20);

    if ($rate < 0) {
        $rate = 0;
    }
    if ($rate > 100) {
        $rate = 100;
    }

    $commission = max(0, round($amount * ($rate / 100), 2));
    $net = max(0, $amount - $commission);

    return array(
        'rate'       => $rate,
        'commission' => $commission,
        'net'        => $net,
    );
}

/**
 * Approve an escrow (manual admin action).
 * - marks escrow as 'approved'
 * - records approver and timestamp
 * - fires lifecycle actions and credits vendor via stakmv_wallet_credit
 *
 * Returns true on success, WP_Error on failure.
 */
function stakmv_approve_escrow($escrow_order_id, $approver_user_id = null) {
    $escrow_order_id = intval($escrow_order_id);
    if ($escrow_order_id <= 0) {
        return new WP_Error('invalid_id', 'Invalid escrow id');
    }

    $status = get_post_meta($escrow_order_id, '_stakmv_escrow_status', true);
    if ($status !== 'pending') {
        return new WP_Error('invalid_status', 'Escrow is not pending');
    }

    $vendor_id = intval(get_post_meta($escrow_order_id, '_stakmv_escrow_vendor', true));
    $amount    = (float) get_post_meta($escrow_order_id, '_stakmv_escrow_amount', true);

    if ($vendor_id <= 0 || $amount <= 0) {
        return new WP_Error('invalid_data', 'Missing vendor or amount');
    }

    // Apply commission consistently for every escrow payout.
    $split = stakmv_calculate_commission_split($amount);
    $commission_rate   = $split['rate'];
    $commission_amount = $split['commission'];
    $net_amount        = $split['net'];

    $approver_user_id = $approver_user_id ? intval($approver_user_id) : get_current_user_id();

    update_post_meta($escrow_order_id, '_stakmv_escrow_status', 'approved');
    update_post_meta($escrow_order_id, '_stakmv_escrow_approved_by', $approver_user_id);
    update_post_meta($escrow_order_id, '_stakmv_escrow_approved_at', current_time('mysql'));
    update_post_meta($escrow_order_id, '_stakmv_commission_rate', $commission_rate);
    update_post_meta($escrow_order_id, '_stakmv_commission_amount', $commission_amount);
    update_post_meta($escrow_order_id, '_stakmv_escrow_net_amount', $net_amount);

    $data = [
        'vendor_id' => $vendor_id,
        'amount'    => $amount,
        'order_id'  => $escrow_order_id,
    ];

    // Notify extensions that escrow was approved
    do_action('stakmv_escrow_approved', $escrow_order_id, $data);

    /**
     * Credit vendor via the wallet action.
     * Extensions can listen to 'stakmv_wallet_credit' and record ledger entries.
     *
     * Signature:
     * do_action('stakmv_wallet_credit', $vendor_id, $amount, $context = null, $meta = []);
     */
    do_action('stakmv_wallet_credit', $vendor_id, $net_amount, $escrow_order_id, [
        'reason'     => 'escrow_approved',
        'gross'      => $amount,
        'commission' => $commission_amount,
        'rate'       => $commission_rate,
    ]);

    return true;
}

/**
 * Mark an escrow as refunded (admin action).
 * - marks escrow as 'refunded'
 * - fires lifecycle action
 */
function stakmv_refund_escrow($escrow_order_id, $actor_user_id = null) {
    $escrow_order_id = intval($escrow_order_id);
    if ($escrow_order_id <= 0) {
        return new WP_Error('invalid_id', 'Invalid escrow id');
    }

    $status = get_post_meta($escrow_order_id, '_stakmv_escrow_status', true);
    if ($status !== 'pending') {
        return new WP_Error('invalid_status', 'Escrow is not pending');
    }

    update_post_meta($escrow_order_id, '_stakmv_escrow_status', 'refunded');
    update_post_meta($escrow_order_id, '_stakmv_escrow_refunded_by', $actor_user_id ?: get_current_user_id());
    update_post_meta($escrow_order_id, '_stakmv_escrow_refunded_at', current_time('mysql'));

    $data = [
        'order_id' => $escrow_order_id,
    ];

    do_action('stakmv_escrow_refunded', $escrow_order_id, $data);

    return true;
}

/**
 * Utility: get pending escrow orders (array of WC_Order objects)
 */
function stakmv_get_pending_escrows($args = []) {
    // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Escrow status/order-type constraints require order meta filtering.
    $defaults = [
        'limit'      => -1,
        'status'     => ['processing', 'completed', 'on-hold', 'pending'],
        'type'       => 'shop_order',
        'meta_query' => [
            [
                'key'   => '_stakmv_escrow_status',
                'value' => 'pending',
            ],
            [
                'key'     => '_stakmv_auction_id',
                'compare' => 'EXISTS',
            ],
        ],
    ];
    // phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_meta_query

    $query = array_merge($defaults, $args);

    // Use wc_get_orders for WP/WC compatibility
    $orders = wc_get_orders($query);
    return $orders;
}

/**
 * Hook into payment complete to create escrow records for auction orders.
 * - ensures escrow exists only once per order
 */
add_action('woocommerce_payment_complete', function ($order_id) {
    stakmv_create_escrow_for_order($order_id);
}, 10, 1);

/**
 * Also hook into order status change to completed (covers some payment gateways)
 */
add_action('woocommerce_order_status_completed', function ($order_id) {
    stakmv_create_escrow_for_order($order_id);
}, 10, 1);

/**
 * Also create escrow on processing to cover gateways that skip "completed".
 */
add_action('woocommerce_order_status_processing', function ($order_id) {
    stakmv_create_escrow_for_order($order_id);
}, 10, 1);

/**
 * Free: Auto-approve escrow if enabled in settings and eligible.
 */
function stakmv_free_maybe_auto_approve_escrow( $order_id ) {

    $order_id = intval( $order_id );
    if ( $order_id <= 0 ) {
        return;
    }

    // Only pending escrows
    $status = get_post_meta( $order_id, '_stakmv_escrow_status', true );
    if ( $status !== 'pending' ) {
        return;
    }

    if ( get_option( 'stakmv_enable_auto_escrow', 'no' ) !== 'yes' ) {
        return;
    }

    $amount = (float) get_post_meta( $order_id, '_stakmv_escrow_amount', true );
    if ( $amount <= 0 ) {
        return;
    }

    $threshold = (float) get_option( 'stakmv_auto_escrow_threshold', 0 );
    $buyer_confirmed = get_post_meta( $order_id, '_stakmv_buyer_confirmed', true ) === 'yes';

    if ( $amount <= $threshold || $buyer_confirmed ) {
        stakmv_approve_escrow( $order_id );
        return;
    }

    // Above threshold without confirmation: check delivery window elapsed
    $days = (int) ( function_exists('stakmv_calculate_expected_delivery_days_for_order') ? stakmv_calculate_expected_delivery_days_for_order( $order_id ) : 0 );

    // If calculation is unavailable, fall back to the vendor delivery estimate.
    if ( $days <= 0 ) {
        $auction_id = get_post_meta( $order_id, '_stakmv_auction_id', true );
        $vendor_id  = $auction_id ? (int) get_post_field( 'post_author', $auction_id ) : 0;
        $days       = $vendor_id ? (int) get_user_meta( $vendor_id, 'stakmv_expected_delivery_days', true ) : 0;
    }

    if ( $days > 0 ) {
        $created_at = get_post_meta( $order_id, '_stakmv_escrow_created_at', true );
        $created_ts = $created_at ? strtotime( $created_at ) : time();
        if ( time() >= ( $created_ts + ( $days * DAY_IN_SECONDS ) ) ) {
            stakmv_approve_escrow( $order_id );
        }
    }
}

add_action( 'stakmv_escrow_created', function( $order_id ) {
    stakmv_free_maybe_auto_approve_escrow( $order_id );
}, 20, 1 );

add_action( 'woocommerce_order_status_completed', function( $order_id ) {
    stakmv_free_maybe_auto_approve_escrow( $order_id );
}, 20, 1 );

add_action( 'woocommerce_order_status_processing', function( $order_id ) {
    stakmv_free_maybe_auto_approve_escrow( $order_id );
}, 20, 1 );
