<?php

namespace SoftminalB2B\Http\Controllers;

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

use SoftminalB2B\Cart\BulkAdder;
use SoftminalB2B\Cart\QuantityRules;
use SoftminalB2B\Pricing\Resolver;
use SoftminalB2B\Services\Settings;

/**
 * Backs the storefront bulk order form (FEATURES F1).
 *
 * The form is for logged-in buyers placing large orders, so the product source
 * is AJAX-paginated: Wholesale Suite froze at 20–30 products because it tried
 * to render the whole catalogue at once, and the acceptance bar here is 100+
 * line items without freezing.
 */
class StorefrontController extends Controller
{
    private const PER_PAGE = 20;

    /**
     * One page of purchasable products, each already priced for this buyer.
     */
    public function products(\WP_REST_Request $request, $params = [])
    {
        $search   = sanitize_text_field((string) $request->get_param('search'));
        $page     = max(1, (int) $request->get_param('page'));
        $category = sanitize_title((string) $request->get_param('category'));
        // Page size: a per-placement override (block/shortcode) wins over the
        // shop-wide setting. Clamped to a sane range either way.
        $perPageParam = $request->get_param('per_page');
        $perPage      = $perPageParam !== null && $perPageParam !== ''
            ? (int) $perPageParam
            : (int) Settings::get('bulk_order_page_size');
        $perPage      = min(200, max(5, $perPage));

        $args = [
            'status'   => 'publish',
            'limit'    => $perPage,
            'page'     => $page,
            'paginate' => true,
            'orderby'  => 'title',
            'order'    => 'ASC',
            // Variations are added through their parent, so list parents only.
            'type'     => ['simple', 'variable'],
        ];

        if ($search !== '') {
            $args['s'] = $search;
        }

        if ($category !== '') {
            // wc_get_products takes category by slug (array), not term id.
            $args['category'] = [$category];
        }

        // Optionally drop out-of-stock products entirely (vs. showing them
        // disabled). Per-placement override wins over the shop-wide setting.
        $hideOosParam = $request->get_param('hide_oos');
        $hideOos      = $hideOosParam !== null && $hideOosParam !== ''
            ? in_array($hideOosParam, ['1', 'yes', 'true'], true)
            : (Settings::get('bulk_order_hide_oos') === 'yes');
        if ($hideOos) {
            $args['stock_status'] = 'instock';
        }

        $results  = wc_get_products($args);
        $products = [];

        foreach ($results->products as $product) {
            $presented = $this->presentProduct($product);

            if ($presented !== null) {
                $products[] = $presented;
            }
        }

        return $this->success([
            'products'  => $products,
            'page'      => $page,
            'per_page'  => $perPage,
            'total'     => (int) $results->total,
            'max_pages' => (int) $results->max_num_pages,
        ]);
    }

    /**
     * Add many lines to the cart in one request.
     *
     * Each line is validated against its quantity rule first, because
     * WC_Cart::add_to_cart() does not apply the add-to-cart validation filter —
     * so without an explicit check a bulk add would bypass min/max/step
     * entirely. Valid lines are added; invalid ones are reported back per line
     * rather than failing the whole submission.
     */
    public function bulkAdd(\WP_REST_Request $request, $params = [])
    {
        if (!function_exists('wc_load_cart')) {
            return $this->error(__('The cart is unavailable right now.', 'softminal-b2b-wholesale-for-woocommerce'), 503);
        }

        $lines = $request->get_param('items');

        if (!is_array($lines) || empty($lines)) {
            return $this->error(__('Add a quantity to at least one product.', 'softminal-b2b-wholesale-for-woocommerce'), 422);
        }

        $result  = BulkAdder::add($lines);
        $added   = $result['added'];
        $skipped = $result['skipped'];

        if ($added === 0 && !empty($skipped)) {
            return $this->response([
                'success' => false,
                'message' => __('None of those lines could be added.', 'softminal-b2b-wholesale-for-woocommerce'),
                'data'    => ['added' => 0, 'skipped' => $skipped, 'cart_count' => WC()->cart->get_cart_contents_count()],
            ], 422);
        }

        return $this->success(
            [
                'added'      => $added,
                'skipped'    => $skipped,
                'cart_count' => WC()->cart->get_cart_contents_count(),
                'cart_total' => (float) WC()->cart->get_cart_contents_total(),
                'cart_url'   => wc_get_cart_url(),
            ],
            sprintf(
                /* translators: %d: number of products added */
                _n('%d product added to your cart.', '%d products added to your cart.', $added, 'softminal-b2b-wholesale-for-woocommerce'),
                $added
            )
        );
    }

    /**
     * Quick order pad: add many products to the cart by SKU, no searching. Each
     * line is a SKU + quantity (pasted or from a CSV). Returns a per-line result
     * so the shopper sees exactly what landed and what didn't — an unknown SKU
     * or a below-minimum quantity is reported, never silently dropped.
     */
    public function quickAdd(\WP_REST_Request $request, $params = [])
    {
        if (!function_exists('wc_load_cart')) {
            return $this->error(__('The cart is unavailable right now.', 'softminal-b2b-wholesale-for-woocommerce'), 503);
        }

        $lines = $request->get_param('lines');

        if (!is_array($lines) || empty($lines)) {
            return $this->error(__('Add at least one SKU and quantity.', 'softminal-b2b-wholesale-for-woocommerce'), 422);
        }

        if (null === WC()->cart) {
            wc_load_cart();
        }

        $added   = 0;
        $results = [];

        foreach ($lines as $line) {
            $sku = sanitize_text_field((string) ($line['sku'] ?? ''));
            $qty = absint($line['qty'] ?? ($line['quantity'] ?? 0));

            if ($sku === '') {
                continue;
            }

            if ($qty <= 0) {
                $results[] = ['sku' => $sku, 'status' => 'invalid', 'reason' => __('needs a quantity', 'softminal-b2b-wholesale-for-woocommerce')];
                continue;
            }

            $id      = wc_get_product_id_by_sku($sku);
            $product = $id ? wc_get_product($id) : null;

            if (!$product) {
                $results[] = ['sku' => $sku, 'status' => 'not_found', 'reason' => __('no product with that SKU', 'softminal-b2b-wholesale-for-woocommerce')];
                continue;
            }

            // A SKU can belong to a variation; resolve it to parent + variation.
            $variationId = $product->is_type('variation') ? (int) $id : 0;
            $productId   = $variationId ? (int) $product->get_parent_id() : (int) $id;

            if (!$product->is_purchasable() || !$product->is_in_stock()) {
                $results[] = ['sku' => $sku, 'name' => $product->get_name(), 'status' => 'unavailable', 'reason' => __('not available to buy', 'softminal-b2b-wholesale-for-woocommerce')];
                continue;
            }

            $rule = QuantityRules::forProduct($productId, $variationId ?: null);

            if ($rule) {
                $violation = $rule->violationFor($qty, $product->get_name());

                if ($violation !== null) {
                    $results[] = ['sku' => $sku, 'name' => $product->get_name(), 'status' => 'invalid_qty', 'reason' => $violation];
                    continue;
                }
            }

            if (WC()->cart->add_to_cart($productId, $qty, $variationId)) {
                $added++;
                $results[] = ['sku' => $sku, 'name' => $product->get_name(), 'qty' => $qty, 'status' => 'added'];
            } else {
                $results[] = ['sku' => $sku, 'name' => $product->get_name(), 'status' => 'error', 'reason' => __('could not be added', 'softminal-b2b-wholesale-for-woocommerce')];
            }
        }

        return $this->success([
            'added'      => $added,
            'results'    => $results,
            'cart_count' => WC()->cart->get_cart_contents_count(),
            'cart_total' => (float) WC()->cart->get_cart_contents_total(),
            'cart_url'   => wc_get_cart_url(),
        ]);
    }

    /**
     * @return array<string, mixed>|null
     */
    private function presentProduct(\WC_Product $product): ?array
    {
        if (!$product->is_purchasable() && !$product->is_type('variable')) {
            return null;
        }

        $productId = $product->get_id();
        $rule      = QuantityRules::forProduct($productId);

        $base = [
            'id'         => $productId,
            'name'       => $product->get_name(),
            'sku'        => $product->get_sku(),
            'type'       => $product->get_type(),
            'image'      => self::imageUrl($product),
            'in_stock'   => $product->is_in_stock(),
            'min_qty'    => $rule && $rule->min_qty !== null ? (int) $rule->min_qty : 1,
            'max_qty'    => $rule && $rule->max_qty !== null ? (int) $rule->max_qty : null,
            'step_qty'   => $rule && $rule->step_qty !== null ? (int) $rule->step_qty : 1,
            'variations' => [],
        ];

        if ($product->is_type('variable')) {
            $base['price_html'] = wp_strip_all_tags($product->get_price_html());

            foreach ($product->get_children() as $childId) {
                $variation = wc_get_product($childId);

                if (!$variation instanceof \WC_Product_Variation || !$variation->is_purchasable()) {
                    continue;
                }

                $resolved = Resolver::resolve($productId, $childId, null, 1);

                $base['variations'][] = [
                    'id'            => $childId,
                    'name'          => wc_get_formatted_variation($variation, true),
                    'sku'           => $variation->get_sku(),
                    // Numeric prices let the client recompute subtotals live;
                    // regular_price drives the "was" strike-through and savings.
                    'price'         => $resolved->price(),
                    'regular_price' => $resolved->basePrice(),
                    'is_discounted' => $resolved->isDiscounted(),
                    'in_stock'      => $variation->is_in_stock(),
                ];
            }
        } else {
            $resolved              = Resolver::resolve($productId, null, null, 1);
            $base['price']         = $resolved->price();
            $base['regular_price'] = $resolved->basePrice();
            $base['is_discounted'] = $resolved->isDiscounted();
        }

        /**
         * A single bulk-order product row before it reaches the storefront form.
         * The Dokan bridge adds a `store` label here so the form stays legible
         * across vendors; on a single-merchant store nothing is added.
         *
         * @param array<string, mixed> $base
         * @param \WC_Product          $product
         */
        return apply_filters('smb2b_bulk_order_product', $base, $product);
    }

    /**
     * A small square thumbnail for the order table, or null so the client can
     * fall back to its placeholder tile. Uses the WooCommerce thumbnail size so
     * the store's own image handling (and any CDN) applies.
     */
    private static function imageUrl(\WC_Product $product): ?string
    {
        $imageId = $product->get_image_id();

        if (!$imageId) {
            return null;
        }

        $src = wp_get_attachment_image_url((int) $imageId, 'woocommerce_thumbnail');

        return $src ?: null;
    }

    /**
     * @return array<string, string>
     */
    private function skip(?\WC_Product $product, string $reason): array
    {
        return [
            'name'   => $product ? $product->get_name() : __('A product', 'softminal-b2b-wholesale-for-woocommerce'),
            'reason' => $reason,
        ];
    }
}
