<?php

namespace Soft_Tehnica\Freya_Sync_Service\Services;

use Exception;
use Soft_Tehnica\Freya_Sync_Service\Data\Notification;
use Soft_Tehnica\Freya_Sync_Service\Data\ToppingListCategory;
use Soft_Tehnica\Freya_Sync_Service\Data\ToppingListItem;
use WC_Product;
use WC_Product_Simple;
use WP_Post;

defined( 'ABSPATH' ) || exit;

class ToppingService
{

    public function __construct()
    {
        $this->register_actions();
    }

    private function register_actions(): void
    {
        add_action( 'add_meta_boxes', [$this, 'add_product_edit_topping_section'] );
        add_action( 'woocommerce_process_product_meta', [$this, 'save_visibility'] );

        add_action( 'woocommerce_before_add_to_cart_button', [$this, 'display_toppings'], 10 );
        add_filter( 'woocommerce_add_cart_item_data', [$this, 'add_toppings_to_cart_item'], 10, 2 );
        add_filter( 'woocommerce_cart_item_name', [$this, 'display_toppings_in_cart'], 10, 3 );
        add_filter( 'woocommerce_order_item_meta_start', [$this, 'display_toppings_on_thank_you'], 10, 3 );
        add_action( 'woocommerce_after_order_itemmeta', [$this, 'display_toppings_on_admin_order_page'], 10, 3 );
        add_filter( 'woocommerce_checkout_create_order_line_item', [$this, 'add_meta_data_to_order_item'], 10, 4 );
        add_action( 'woocommerce_before_calculate_totals', [$this, 'update_cart_item_prices'], 10, 1 );
        add_filter( 'woocommerce_get_price_html', [$this, 'add_topping_price_div'] );
        // Validare coș (fără ajax)
        add_filter( 'woocommerce_add_to_cart_validation', [$this, 'validate_cart_item_old'], 10, 2 );
        // Validare coș (cu ajax) - woocommerce >= 7.1
        add_filter( 'woocommerce_store_api_validate_add_to_cart', [$this, 'validate_cart_item_new'] );
    }

    public function add_topping_price_div( $price ): string
    {
        $price .= ' <span id="fsToppingTotal" class="fss-hide woocommerce-Price-amount amount"></span>';

        return $price;
    }

    /**
     * @ajax fss_get_toppings
     */
    public function get_toppings_for_product(): void
    {
        check_ajax_referer( 'wp_rest', 'nonce' );

        if ( !$_REQUEST['id'] ) {
            wp_send_json_error( null, 400 );

            return;
        }

        $product = wc_get_product( $_REQUEST['id'] );

        if ( !$product ) {
            wp_send_json_error( null, 404 );

            return;
        }

        $toppings = $product->get_meta( 'freya_sync_toppings', true );

        if ( is_array( $toppings ) && count( $toppings ) > 0 ) {
            wp_send_json_success( [
                'productPrice' => floatval( $product->get_price() ),
                'toppings'     => $toppings,
            ], 200 );

            return;
        }

        wp_send_json_error( null, 404 );
    }

    public function update_cart_item_prices( \WC_Cart $cart ): void
    {
        if ( is_admin() && !defined( 'DOING_AJAX' ) ) {
            return;
        }

        if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) {
            return;
        }

        foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
            if ( !isset( $cart_item['freya_sync_toppings'] ) ) {
                continue;
            }

            $price = floatval( $cart_item['data']->get_price() );

            foreach ( $cart_item['freya_sync_toppings'] as $topping ) {
                $price += $topping['price'];
            }

            $cart_item['data']->set_price( $price );
        }
    }

    public function add_toppings_to_cart_item( $cart_item_data, $product_id )
    {
        $product = wc_get_product( $product_id );

        if ( !$product ) {
            return $cart_item_data;
        }

        $meta_data = $product->get_meta( 'freya_sync_toppings' );

        if ( !$meta_data || !count( $meta_data ) > 0 ) {
            return $cart_item_data;
        }

        foreach ( $meta_data as $meta ) {
            if ( !isset( $meta['freyaCode'] ) ) {
                continue;
            }

            $isChecked = isset( $_POST[$meta['freyaCode']] );

            if ( !$isChecked ) {
                continue;
            }

            if ( !isset( $cart_item_data['freya_sync_toppings'] ) ) {
                $cart_item_data['freya_sync_toppings'] = [];
            }

            $cart_item_data['freya_sync_toppings'][] = [
                'name'      => $meta['name'],
                'price'     => $meta['price'],
                'freyaCode' => $meta['freyaCode'],
            ];
        }

        return $cart_item_data;
    }

    public function add_meta_data_to_order_item( $item, $cart_item_key, $values, $order )
    {
        $this->add_toppings_to_order_item( $item, $cart_item_key, $values, $order );

        return $item;
    }

    public function add_toppings_to_order_item( &$item, $cart_item_key, $values, $order )
    {
        if ( !isset( $values['freya_sync_toppings'] ) ) {
            return $item;
        }

        $item->add_meta_data( '_freya_sync_toppings', $values['freya_sync_toppings'] );
        $item->add_meta_data( '_freya_sync_subtract_toppings_from_price', true );
    }

    public function display_toppings_on_admin_order_page( $itemId, \WC_Order_Item $item, ?WC_Product $product ): void
    {
        $toppings = $item->get_meta( '_freya_sync_toppings' );

        if ( !$toppings || !is_array( $toppings ) ) {
            return;
        }

        ?>
        <ul class="fss-cart-topping-list">
            <?php foreach ( $toppings as $topping ) { ?>
                <?php $formatted_price = wc_price( $topping['price'] ); ?>
                <li><?php printf( '%s (+ %s)', $topping['name'], $formatted_price ); ?></li>
            <?php } ?>
        </ul>
        <?php
    }

    public function display_toppings_in_cart( $name, $cart_item, $cart_item_key ): string
    {
        if ( !isset( $cart_item['freya_sync_toppings'] ) ) {
            return $name;
        }

        /** @var WC_Product_Simple $cart_product */
        $cart_product = $cart_item['data'];

        $product = wc_get_product( $cart_product->get_id() );

        if ( !$product ) {
            return $name;
        }

        $formatted_price = wc_price( $product->get_price() );

        $name .= "&nbsp;<span class=\"fss-cart-base-price\">($formatted_price)</span>";
        $name .= "<ul class='fss-cart-topping-list'>";

        foreach ( $cart_item['freya_sync_toppings'] as $topping ) {
            $formatted_price = wc_price( $topping['price'] );
            $name .= "<li> + {$topping['name']} (+ {$formatted_price})</li>";
        }
        $name .= '</ul>';

        return $name;
    }

    public function display_toppings_on_thank_you( int $item_id, \WC_Order_Item_Product $item, \WC_Order $order ): void
    {
        $toppings = $item->get_meta( '_freya_sync_toppings' );

        if ( !$toppings ) {
            return;
        }

        $product = $item->get_product();

        if ( !$product ) {
            return;
        }

        ?>
        <span class="fss-cart-base-price"><?php echo sprintf( '(%s)', wc_price( $product->get_price() ) ); ?></span>
        <ul class="fss-cart-topping-list">
            <?php foreach ( $toppings as $topping ) { ?>
                <li><?php echo sprintf( '%s (+%s)', $topping['name'], wc_price( $topping['price'] ) ); ?></li>
            <?php } ?>
        </ul>
        <?php
    }

    public function display_toppings(): void
    {
        global $post;
        /** @var WP_Post $post */
        $product  = wc_get_product( $post->ID );
        $toppings = $this->create_topping_list( $product, true );

        if ( is_null( $toppings ) ) {
            return;
        }
        $price    = floatval( $product->get_price() );
        $pricestr = number_format( $price, 2, '.', '' );

        ?>
        <div id="FS_TOPPING_PARENT_ID" class="hidden" data-id="<?php echo $post->ID; ?>" data-price="<?php echo $pricestr; ?>">
            <h2 class='fss-product-topping-title'>Extra-uri</h2>
            <?php foreach ( $toppings as $category ) { ?>
                <?php $toppingCount = count( $category->toppings ); ?>
                <?php if ( count( $category->toppings ) > 0 ) { ?>
                    <?php if ( $category->id !== -1 ) { ?>
                        <h3><?php echo $category->name; ?></h3>
                    <?php } else { ?>
                        <h3>Altele</h3>
                    <?php } ?>
                    <?php foreach ( $category->toppings as $topping ) { ?>
                        <?php
                        $params = [
                            'type'        => 'checkbox',
                            'required'    => ( $category->minOptions ?? 0 ) >= 1,
                            'class'       => ['input-checkbox'],
                            'label_class' => ['fss-topping-checkbox'],
                            'label'       => sprintf(
                                '%s (+%s)',
                                $topping->name,
                                wc_price( $topping->price )
                            ),
                            'id'                => "checkbox-{$topping->freyaCode}",
                            'custom_attributes' => [
                                'data-categoryid'    => $category->id,
                                'data-category-name' => $category->name,
                                'data-topping-price' => number_format( $topping->price, 2, '.', '' ),
                                'data-freya-code'    => $topping->freyaCode,
                                'data-minoptions'    => $category->minOptions,
                                'data-maxoptions'    => $category->maxOptions,
                            ],
                        ];

                        $minOptions = $category->minOptions;
                        $maxOptions = $category->maxOptions;

                        if (
                            $minOptions === $toppingCount &&
                            $maxOptions === $toppingCount
                        ) {
                            $params['custom_attributes']['data-autocheck'] = 1;
                        }

                        woocommerce_form_field( $topping->freyaCode, $params );
                        ?>
                    <?php } ?>
                <?php } ?>
            <?php } ?>
        </div>
        <?php
    }

    private function getHeaderMinMax( ?int $minOptions, ?int $maxOptions, int $toppingCount ): ?string
    {
        $arr = [];
        $ok  = false;

        if ( !is_null( $minOptions ) && !is_null( $maxOptions ) && $minOptions === $maxOptions ) {
            if ( $minOptions > $toppingCount ) {
                return null;
            }

            $display = min( $minOptions, $toppingCount );

            return "alegeți $display";
        }

        if ( !is_null( $minOptions ) && $minOptions > 0 ) {
            $arr[] = sprintf( 'minim %d', min( $minOptions, $toppingCount ) );
            $ok    = true;
        }

        if ( !is_null( $maxOptions ) && $maxOptions > 0 && $maxOptions < $toppingCount ) {
            $arr[] = sprintf( 'maxim %d', $maxOptions );
            $ok    = true;
        }

        if ( $ok ) {
            return implode( ', ', $arr );
        } else {
            return null;
        }
    }

    /**
     * @hook woocommerce_add_to_cart_validation
     */
    public function validate_cart_item_old(
        bool $passed,
        int $product_id
    ): bool {
        if ( fss_is_wc_store_api() ) {
            return $passed;
        }

        $product = wc_get_product( $product_id );

        if ( !$product ) {
            return $passed;
        }

        try {
            $this->count_validate( $product );

            return true;
        } catch ( Exception $e ) {
            NotificationManager::get()->push( new Notification(
                'error',
                $e->getMessage()
            ) );

            return false;
        }
    }

    /**
     * @hook woocommerce_store_api_validate_add_to_cart
     *
     * woocommerce >= 7.2
     */
    public function validate_cart_item_new( WC_Product $product ): void
    {
        $this->count_validate( $product );
    }

    /**
     * @hook add_meta_boxes
     */
    public function add_product_edit_topping_section(): void
    {
        global $post;

        /** @var WP_Post $post */
        if ( !$post ) {
            return;
        }

        $product = wc_get_product( $post->ID );

        if ( !$product ) {
            return;
        }

        add_meta_box(
            'fss-topping-panel',
            __( 'Ascundere extra-uri', 'woocommerce' ),
            [$this, 'product_edit_visibility_toggle'],
            'product',
            'normal',
            'default'
        );
    }

    public function product_edit_visibility_toggle( WP_Post $post ): void
    {
        $product = wc_get_product( $post->ID );

        if ( !$product ) {
            return;
        }

        $list = $this->create_topping_list( $product );

        if ( !$list ) {
            return;
        }

        $visibility = $product->get_meta( '_fss_topping_visibility' );

        ?>
        <div class="fss-options-panel">
            <div class="options-group">
                <p>Opțiunile bifate vor fi <strong>ascunse</strong> pe pagina produsului.</p>
            </div>
            <div class="options-group fss-topping-visibility-list">
            <?php foreach ( $list as $category ) { ?>
                <h3>
                    <?php
                        $minmax = $this->getHeaderMinMax( $category->minOptions, $category->maxOptions, count( $category->toppings ) );
                printf(
                    '%s %s',
                    $category->name,
                    !is_null( $minmax ) ? "($minmax)" : ''
                );
                ?>
                </h3>
                <div class="fss-flow fss-topping-visibility-category">
                <?php foreach ( $category->toppings as $topping ) { ?>
                    <div class="fss-form-control">
                        <?php
                        $id = sprintf( 'fss-topping-cbox-%s', $topping->freyaCode );
                    ?>
                        <input type="checkbox" 
                            id="<?php echo $id; ?>"
                            name="_fss_topping_visibility[]"
                            <?php if ( isset( $visibility[$topping->freyaCode] ) ) {
                                echo 'checked';
                            } ?>
                            value="<?php echo $topping->freyaCode; ?>"
                        />
                        <label for="<?php echo $id; ?>">
                            <?php echo $topping->name; ?>
                        </label>
                    </div>
                <?php } ?>
                </div>
            <?php } ?>
            </div>
        </div>
        <?php
    }

    /**
     * @hook woocommerce_process_product_meta
     */
    public function save_visibility( int $post_id ): void
    {
        $product = wc_get_product( $post_id );

        if ( !$product ) {
            return;
        }

        if ( !isset( $_POST['_fss_topping_visibility'] ) ) {
            $product->delete_meta_data( '_fss_topping_visibility' );
        } else {
            $data = [];

            foreach ( $_POST['_fss_topping_visibility'] as $id ) {
                $data[$id] = $id;
            }
            $product->update_meta_data( '_fss_topping_visibility', $data );
        }

        $product->save_meta_data();
    }

    /**
     * @throws Exception
     */
    private function count_validate( WC_Product $product ): void
    {
        /** @var array<int, int> $minCount */
        $minCount = [];
        /** @var array<int, int> $maxCount */
        $maxCount = [];

        $categories = $this->create_topping_list( $product );

        if ( !$categories ) {
            return;
        }

        foreach ( $categories as $id => $category ) {
            $hasNoLimits = !isset( $category->minOptions ) && !isset( $category->maxOptions );

            if ( $hasNoLimits || $id === -1 ) {
                continue;
            }

            foreach ( $category->toppings as $topping ) {
                if ( !isset( $_POST[$topping->freyaCode] ) ) {
                    continue;
                }

                if ( !is_null( $category->minOptions ) ) {
                    if ( !array_key_exists( $id, $minCount ) ) {
                        $minCount[$id] = 1;
                    } else {
                        $minCount[$id]++;
                    }
                }

                if ( !is_null( $category->maxOptions ) ) {
                    if ( !array_key_exists( $id, $maxCount ) ) {
                        $maxCount[$id] = 1;
                    } else {
                        $maxCount[$id]++;
                    }

                    // Putem să facem early break aici
                    if ( $maxCount[$id] > $category->maxOptions ) {
                        throw new Exception( sprintf( 'Pentru a adăuga produsul în coș, vă rugăm să bifați maxim %d opțiuni pentru %s (ați bifat %d).', $category->maxOptions, $category->name, $maxCount[$id] ) );
                    }
                }
            }
        }

        foreach ( $categories as $id => $category ) {
            if ( is_null( $category->minOptions ) || $category->minOptions === 0 ) {
                continue;
            }

            $selected = $minCount[$id] ?? 0;

            if ( $category->minOptions > $selected ) {
                if ( $category->minOptions === 1 ) {
                    throw new Exception( sprintf( 'Pentru a adăuga produsul în coș, vă rugăm să bifați opțiunea %s', $category->name ) );
                } else {
                    throw new Exception( sprintf( 'Pentru a adăuga produsul în coș, vă rugăm să alegeți minim %d opțiuni pentru %s (ați bifat %d).', $category->minOptions, $category->name, $selected ) );
                }
            }
        }
    }

    /**
     * @return array<int, ToppingListCategory>|null
     */
    private function create_topping_list( WC_Product $product, bool $without_invisible = false ): ?array
    {
        $meta_data = $product->get_meta( 'freya_sync_toppings' );
        /** @var array<int, ToppingListCategory> $ret */
        $ret = [];

        if ( $without_invisible ) {
            $invisible = $product->get_meta( '_fss_topping_visibility' );
        } else {
            $invisible = [];
        }

        if ( !is_array( $meta_data ) || count( $meta_data ) === 0 ) {
            return null;
        }

        foreach ( $meta_data as $topping ) {
            // Minimul necesar pentru topping
            if ( !isset( $topping['name'] ) || !isset( $topping['freyaCode'] ) || !isset( $topping['price'] ) ) {
                continue;
            }

            $toppingItem = new ToppingListItem(
                $topping['name'],
                $topping['price'],
                $topping['freyaCode'],
                $topping['vatRate'] ?? 0.0,
                $topping['orderFlag'] ?? null
            );

            if ( $without_invisible && isset( $invisible[$toppingItem->freyaCode] ) ) {
                continue;
            }

            if ( isset( $topping['categoryId'] ) && isset( $topping['categoryName'] ) ) {
                if ( !array_key_exists( $topping['categoryId'], $ret ) ) {
                    $ret[$topping['categoryId']] = new ToppingListCategory(
                        $topping['categoryId'],
                        $topping['categoryName'],
                        $topping['minOptions'] ?? null,
                        $topping['maxOptions'] ?? null,
                        $topping['categoryOrderFlag'] ?? null,
                        [$toppingItem]
                    );
                } else {
                    $ret[$topping['categoryId']]->toppings[] = $toppingItem;
                }
            } else {
                if ( !array_key_exists( -1, $ret ) ) {
                    $ret[-1] = new ToppingListCategory(
                        -1,
                        '',
                        null,
                        null,
                        PHP_INT_MIN,
                        [$toppingItem]
                    );
                }
                $ret[-1]->toppings[] = $toppingItem;
            }
        }

        if ( $without_invisible ) {
            $ret = array_filter( $ret, fn ( ToppingListCategory $i ) => count( $i->toppings ) > 0 );
        }

        usort( $ret, function ( $x, $y ) {
            // Comparăm după order flag doar dacă sunt setate
            if ( !is_null( $x->orderFlag ) && !is_null( $y->orderFlag ) ) {
                return $x->orderFlag - $y->orderFlag;
            }

            if ( $x->name === '' ) {
                return 1;
            } elseif ( $y->name === '' ) {
                return -1;
            } else {
                return strcmp( $x->name, $y->name );
            }
        } );

        foreach ( $ret as $category ) {
            usort( $category->toppings, fn ( $x, $y ) => strcmp( $x->name, $y->name ) );
        }

        return $ret;
    }
}
