<?php

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

if ( ! function_exists( 'bwdk_can_auto_move_to_processing' ) ) {
    function bwdk_dx_status_debug_enabled(): bool {
        return defined( 'BWDK_DX_STATUS_DEBUG' ) && (bool) BWDK_DX_STATUS_DEBUG;
    }

    function bwdk_dx_status_backtrace_summary( int $max = 8 ): string {
        if ( ! function_exists( 'wp_debug_backtrace_summary' ) ) {
            $bt = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, max( 1, $max + 1 ) );
            $out = [];
            foreach ( $bt as $i => $f ) {
                if ( $i === 0 ) {
                    continue;
                }
                $fn = ( $f['class'] ?? '' ) . ( $f['type'] ?? '' ) . ( $f['function'] ?? '' );
                $file = $f['file'] ?? '';
                $line = isset( $f['line'] ) ? (string) $f['line'] : '';
                $out[] = $fn . ( $file !== '' ? ( ' @ ' . $file . ':' . $line ) : '' );
                if ( count( $out ) >= $max ) {
                    break;
                }
            }
            return implode( ' | ', $out );
        }

        $summary = wp_debug_backtrace_summary( null, $max, 'string' );
        if ( is_array( $summary ) ) {
            return implode( ' | ', $summary );
        }

        return (string) $summary;
    }

    /**
     * Minimal HPOS status-save debug log (BWDK_DX_STATUS_DEBUG only).
     *
     * @param string               $step
     * @param int                  $order_id
     * @param array<string, mixed> $extra
     */
    function bwdk_dx_status_log_hpos_step( string $step, int $order_id, array $extra = [] ): void {
        if ( ! bwdk_dx_status_debug_enabled() || $order_id <= 0 || ! function_exists( 'wc_get_order' ) ) {
            return;
        }

        $fresh = wc_get_order( $order_id );
        if ( ! $fresh instanceof \WC_Order ) {
            return;
        }

        $posted_raw = isset( $_POST['order_status'] ) ? (string) $_POST['order_status'] : '';
        $posted     = function_exists( 'bwdk_normalize_admin_posted_order_status' )
            ? bwdk_normalize_admin_posted_order_status()
            : '';

        $hpos_status = '';
        global $wpdb;
        if ( isset( $wpdb ) ) {
            $table = $wpdb->prefix . 'wc_orders';
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $raw = $wpdb->get_var( $wpdb->prepare( "SELECT status FROM {$table} WHERE id = %d", $order_id ) );
            if ( is_string( $raw ) ) {
                $hpos_status = (string) preg_replace( '/^wc-/', '', $raw );
            }
        }

        $payload = array_merge(
            [
                'step'           => $step,
                'order_id'       => $order_id,
                'posted_raw'     => $posted_raw,
                'posted'         => $posted,
                'db_status'      => (string) $fresh->get_status(),
                'hpos_table'     => $hpos_status,
                'requested_meta' => preg_replace( '/^wc-/', '', (string) $fresh->get_meta( '_bwdk_admin_requested_status', true ) ),
                'lock_meta'      => (int) $fresh->get_meta( '_bwdk_admin_manual_status_lock', true ),
                'hook'           => function_exists( 'current_action' ) ? (string) current_action() : '',
            ],
            $extra
        );

        if ( $posted === 'completed' && $fresh->get_status() === 'processing' ) {
            $payload['backtrace'] = bwdk_dx_status_backtrace_summary( 8 );
        }

        error_log( '[BWDK DX STATUS DEBUG] ' . wp_json_encode( $payload ) );
    }

    /**
     * Normalize admin POST status (wc-completed, completed, etc.).
     */
    function bwdk_normalize_admin_posted_order_status( $raw = null ): string {
        if ( $raw === null ) {
            if ( isset( $_POST['order_status'] ) ) {
                $raw = $_POST['order_status'];
            } elseif ( isset( $_POST['status'] ) ) {
                $raw = $_POST['status'];
            } else {
                return '';
            }
        }

        $raw = wc_clean( wp_unslash( (string) $raw ) );

        return (string) preg_replace( '/^wc-/', '', $raw );
    }

    /**
     * HPOS Orders admin screen (woocommerce_page_wc-orders).
     */
    function bwdk_is_hpos_orders_admin_screen(): bool {
        if ( ! is_admin() ) {
            return false;
        }

        if ( isset( $_GET['page'] ) && (string) $_GET['page'] === 'wc-orders' ) {
            return true;
        }

        $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
        if ( is_object( $screen ) && isset( $screen->id ) ) {
            return strpos( (string) $screen->id, 'wc-orders' ) !== false;
        }

        return false;
    }

    /**
     * Resolve order ID from HPOS/classic admin order edit request.
     */
    function bwdk_resolve_admin_order_id_from_request(): int {
        $keys = [ 'id', 'post', 'post_ID', 'order_id' ];
        foreach ( $keys as $key ) {
            foreach ( [ $_GET, $_POST, $_REQUEST ] as $source ) {
                if ( isset( $source[ $key ] ) ) {
                    $id = absint( $source[ $key ] );
                    if ( $id > 0 ) {
                        return $id;
                    }
                }
            }
        }

        return 0;
    }

    function bwdk_is_admin_manual_status_change_to_final( \WC_Order $order ): bool {
        if ( ! is_admin() ) {
            return false;
        }

        if ( ! $order->get_meta( '_bwdk_order_uuid' ) ) {
            return false;
        }

        $posted_status = function_exists( 'bwdk_normalize_admin_posted_order_status' )
            ? bwdk_normalize_admin_posted_order_status()
            : '';

        $final_statuses = array(
            'completed',
            'cancelled',
            'refunded',
            'failed',
        );

        return in_array( $posted_status, $final_statuses, true );
    }

    /**
     * True while wp-admin is saving a shop order with an explicit status in the request.
     * Used to skip DigiExpress auto-refresh that reloads the order and can roll back in-flight status.
     */
    function bwdk_is_admin_order_status_save_in_progress(): bool {
        if ( ! is_admin() ) {
            return false;
        }

        $in_save_hook = doing_action( 'woocommerce_admin_process_shop_order_object' )
            || doing_action( 'woocommerce_before_order_object_save' )
            || doing_action( 'woocommerce_after_order_object_save' );

        if ( ! $in_save_hook
            && ( ! isset( $_POST['order_status'] ) && ! isset( $_POST['status'] ) )
            && ! ( function_exists( 'bwdk_is_hpos_orders_admin_screen' ) && bwdk_is_hpos_orders_admin_screen() ) ) {
            return false;
        }

        $posted_status = function_exists( 'bwdk_normalize_admin_posted_order_status' )
            ? bwdk_normalize_admin_posted_order_status()
            : '';

        return $posted_status !== '';
    }

    function bwdk_has_recent_admin_manual_status_lock( \WC_Order $order, int $ttl_seconds = 300 ): bool {
        if ( ! $order->get_meta( '_bwdk_order_uuid' ) ) {
            return false;
        }

        $lock_time = (int) $order->get_meta( '_bwdk_admin_manual_status_lock', true );
        if ( $lock_time <= 0 ) {
            return false;
        }

        return ( time() - $lock_time ) < $ttl_seconds;
    }

    /**
     * Skip automatic WC status writes (e.g. DigiExpress webhook) while admin manual lock is active.
     * Does not block admin save — only automatic overrides.
     */
    function bwdk_should_skip_automatic_wc_status_override( \WC_Order $order ): bool {
        if ( ! $order->get_meta( '_bwdk_order_uuid' ) ) {
            return false;
        }

        if ( function_exists( 'bwdk_is_admin_manual_status_change_to_final' ) && bwdk_is_admin_manual_status_change_to_final( $order ) ) {
            return true;
        }

        if ( function_exists( 'bwdk_has_recent_admin_manual_status_lock' ) && bwdk_has_recent_admin_manual_status_lock( $order, 300 ) ) {
            return true;
        }

        return false;
    }

    function bwdk_can_auto_move_to_processing( \WC_Order $order ): bool {
        if ( ! $order->get_meta( '_bwdk_order_uuid' ) ) {
            return false;
        }

        if ( function_exists( 'bwdk_is_admin_manual_status_change_to_final' ) && bwdk_is_admin_manual_status_change_to_final( $order ) ) {
            return false;
        }

        if ( function_exists( 'bwdk_has_recent_admin_manual_status_lock' ) && bwdk_has_recent_admin_manual_status_lock( $order, 300 ) ) {
            return false;
        }

        if ( $order->get_meta( '_bwdk_auto_processing_done' ) === 'yes' ) {
            return false;
        }

        $current_status = $order->get_status();

        $blocked_statuses = array(
            'processing',
            'completed',
            'refunded',
            'failed',
        );

        if ( in_array( $current_status, $blocked_statuses, true ) ) {
            return false;
        }

        $allowed_statuses = array(
            'pending',
            'on-hold',
            'cancelled',
            'bwdk-verifying',
            'bwdk-verified',
        );

        return in_array( $current_status, $allowed_statuses, true );
    }
}

