<?php

namespace Kitgenix\PDF_Invoicing\Modules\Admin;

use Kitgenix\PDF_Invoicing\Core\ModuleInterface;

defined( 'ABSPATH' ) || exit;

/**
 * Adds a "Has PDF documents" filter dropdown to the WooCommerce orders
 * admin list, so support staff can find orders by document state without
 * opening each order. Wired for both storage backends:
 *  - Legacy (shop_order post type): `restrict_manage_posts` + `pre_get_posts`.
 *  - HPOS (custom order tables): `woocommerce_order_list_table_restrict_manage_orders`
 *    + `woocommerce_order_query_args` (the filter WC_Order_Query itself exposes,
 *    which the HPOS list table is built on) – the public, documented way to
 *    extend HPOS order queries rather than querying custom tables directly.
 */
final class OrderListFilter implements ModuleInterface {

    private const QUERY_VAR = 'kitgenix_doc_filter';

    public function get_id(): string {
        return 'order_list_filter';
    }

    public function register(): void {
        add_action( 'restrict_manage_posts', [ $this, 'render_filter' ], 10, 2 );
        add_action( 'woocommerce_order_list_table_restrict_manage_orders', [ $this, 'render_filter_hpos' ], 10, 2 );

        add_action( 'pre_get_posts', [ $this, 'filter_legacy_query' ] );
        add_filter( 'woocommerce_order_query_args', [ $this, 'filter_order_query_args' ] );
    }

    /**
     * @return array<string,string>
     */
    private function get_filter_options(): array {
        return [
            ''                => __( 'All documents', 'kitgenix-pdf-invoicing-for-woocommerce' ),
            'has_invoice'     => __( 'Has invoice', 'kitgenix-pdf-invoicing-for-woocommerce' ),
            'no_invoice'      => __( 'No invoice yet', 'kitgenix-pdf-invoicing-for-woocommerce' ),
            'has_credit_note' => __( 'Has credit note', 'kitgenix-pdf-invoicing-for-woocommerce' ),
        ];
    }

    private function get_selected_filter(): string {
        /* phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only list-table filter selection, not a state-changing action. */
        $value = isset( $_GET[ self::QUERY_VAR ] ) ? sanitize_key( wp_unslash( $_GET[ self::QUERY_VAR ] ) ) : '';

        return array_key_exists( $value, $this->get_filter_options() ) ? $value : '';
    }

    public function render_filter( string $post_type, string $which ): void {
        if ( 'shop_order' !== $post_type || 'top' !== $which ) {
            return;
        }

        $this->render_filter_markup();
    }

    public function render_filter_hpos(): void {
        $this->render_filter_markup();
    }

    private function render_filter_markup(): void {
        $selected = $this->get_selected_filter();
        ?>
        <select name="<?php echo esc_attr( self::QUERY_VAR ); ?>">
            <?php foreach ( $this->get_filter_options() as $value => $label ) : ?>
                <option value="<?php echo esc_attr( $value ); ?>" <?php selected( $selected, $value ); ?>><?php echo esc_html( $label ); ?></option>
            <?php endforeach; ?>
        </select>
        <?php
    }

    /**
     * @return array{key?:string,compare?:string}|null
     */
    private function get_meta_query_clause(): ?array {
        switch ( $this->get_selected_filter() ) {
            case 'has_invoice':
                return [ 'key' => '_kitgenix_pdf_invoicing_for_woocommerce_invoice_number', 'compare' => 'EXISTS' ];

            case 'no_invoice':
                return [ 'key' => '_kitgenix_pdf_invoicing_for_woocommerce_invoice_number', 'compare' => 'NOT EXISTS' ];

            case 'has_credit_note':
                return [ 'key' => '_kitgenix_pdf_invoicing_for_woocommerce_credit_note_refund_map', 'compare' => 'EXISTS' ];
        }

        return null;
    }

    public function filter_legacy_query( \WP_Query $query ): void {
        if ( is_admin() && $query->is_main_query() && 'shop_order' === $query->get( 'post_type' ) ) {
            $clause = $this->get_meta_query_clause();
            if ( null !== $clause ) {
                $meta_query   = (array) $query->get( 'meta_query' );
                $meta_query[] = $clause;
                $query->set( 'meta_query', $meta_query );
            }
        }
    }

    public function filter_order_query_args( array $args ): array {
        if ( ! is_admin() ) {
            return $args;
        }

        $clause = $this->get_meta_query_clause();
        if ( null === $clause ) {
            return $args;
        }

        $meta_query   = isset( $args['meta_query'] ) && is_array( $args['meta_query'] ) ? $args['meta_query'] : [];
        $meta_query[] = $clause;
        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- adding a meta_query clause to the admin order-list query args is the only way to filter that screen by this plugin's own document-status meta.
        $args['meta_query'] = $meta_query;

        return $args;
    }
}
