<?php
/**
 * Builds eMAG offer/save payloads from WooCommerce product/variation data.
 *
 * Endpoint: POST /offer/save  (light API – updates existing offers only)
 *
 * Required field: id (vendor_ext_id from bootstrap)
 * Optional fields sent: sale_price, stock, vat_id, status, handling_time
 *
 * @package SkyEmagSync
 */

namespace SkyEmagSync\Api;

use SkyEmagSync\Options;
use SkyEmagSync\PostMeta;

defined( 'ABSPATH' ) || exit;

class OfferPayload {

    const DEFAULT_WAREHOUSE_ID = 1;
    const MAX_STOCK            = 65535;

    // ── Main factory ─────────────────────────────────────────────────────

    /**
     * Build offer/save payload for a WC product/variation.
     *
     * Returns null if product is not eligible (no vendor_ext_id, wc_stock=0).
     *
     * @param \WC_Product $product
     * @return array|null
     */
    public static function from_product( \WC_Product $product ): ?array {
        $post_id       = $product->get_id();
        $vendor_ext_id = PostMeta::get_vendor_ext_id( $post_id );

        if ( null === $vendor_ext_id ) {
            return null; // not mapped yet
        }

        // Stock — null means WC stock is 0 (skip sync), int≥0 means send to eMAG
        $emag_stock = self::computed_stock( $product );
        if ( null === $emag_stock ) {
            return null; // wc_stock = 0, nothing to sync
        }

        $payload = [
            'id'     => $vendor_ext_id,
            'stock'  => [
                [ 'warehouse_id' => self::DEFAULT_WAREHOUSE_ID, 'value' => $emag_stock ],
            ],
            'status' => self::effective_emag_status( $product ),
        ];

        // Price
        $price = self::computed_price( $product );
        if ( null !== $price ) {
            $payload['sale_price'] = $price;

            $source = self::source_price( $product );
            if ( null !== $source && $source > 0 ) {
                // max_sale_price — upper bound eMAG will accept on future updates.
                $max_marg = self::effective_max_margin( $product );
                $payload['max_sale_price'] = round( $source * ( 1 + $max_marg / 100 ), 2 );

                // min_sale_price — lower bound, driven by the user's min_margin.
                // Sending it on every save keeps eMAG's stored minimum in sync
                // with our local effective_min_margin, so the seller can lower
                // a product's margin later without hitting "below minimum" rejection.
                $min_marg = self::effective_min_margin( $product );
                $payload['min_sale_price'] = round( $source * ( 1 + $min_marg / 100 ), 2 );
            }
        }

        // VAT
        $vat_id = PostMeta::get_vat_id( $post_id );
        if ( null !== $vat_id ) {
            $payload['vat_id'] = $vat_id;
        }

        // Handling time
        $handling = PostMeta::get_handling_time( $post_id );
        $payload['handling_time'] = [
            [ 'warehouse_id' => self::DEFAULT_WAREHOUSE_ID, 'value' => $handling ],
        ];

        return $payload;
    }

    /**
     * Inactive payload – sent when a product is deleted or disabled on eMAG.
     */
    public static function inactive( int $vendor_ext_id ): array {
        return [ 'id' => $vendor_ext_id, 'status' => 0 ];
    }

    // ── Price ─────────────────────────────────────────────────────────────

    public static function computed_price( \WC_Product $product ): ?float {
        $source = self::source_price( $product );
        if ( null === $source || $source <= 0 ) {
            return null;
        }
        $margin = self::effective_margin( $product );
        return self::apply_rounding( $source * ( 1 + $margin / 100 ) );
    }

    public static function source_price( \WC_Product $product ): ?float {
        $fresh = wc_get_product( $product->get_id() );
        if ( ! $fresh ) {
            return null;
        }

        // Price source: regular price (ignore WC sale) when the user has
        // opted in, otherwise the currently active price (sale if running,
        // else regular). Falls back to get_price() if regular_price is blank.
        if ( \SkyEmagSync\Options::use_regular_price() ) {
            $regular   = (float) $fresh->get_regular_price();
            $raw_price = $regular > 0 ? $regular : (float) $fresh->get_price();
        } else {
            $raw_price = (float) $fresh->get_price();
        }
        if ( $raw_price <= 0 ) {
            return null;
        }

        // WooCommerce stores prices either with or without tax depending on the
        // "Prices entered with tax" setting. We need the price WITHOUT tax
        // to send to eMAG (eMAG adds its own VAT display on top).
        //
        // Strategy: use the eMAG vat_id stored during bootstrap to determine
        // the correct VAT rate (11% or 21%), then divide accordingly.
        // This avoids relying on WooCommerce's tax class configuration which
        // may be set to a different rate (e.g. 9% standard WC rate for RO).
        $post_id = $fresh->get_id();
        $vat_id  = PostMeta::get_vat_id( $post_id );
        $vat_rate = null;

        if ( null !== $vat_id ) {
            // Use the rate stored during bootstrap from eMAG /vat/read
            $vat_rate = \SkyEmagSync\Options::vat_rate_for_id( $vat_id );
        }

        // Check if WooCommerce stores prices WITH tax included
        $prices_include_tax = wc_prices_include_tax();

        if ( $prices_include_tax ) {
            if ( null !== $vat_rate && $vat_rate > 0 ) {
                // Divide by eMAG's known rate — reliable
                return round( $raw_price / ( 1 + $vat_rate ), 4 );
            } else {
                // Bootstrap not done yet — fall back to WC's own tax exclusion
                // This may be inaccurate if WC tax class ≠ eMAG VAT rate,
                // but it's the best we can do before bootstrap runs.
                return (float) wc_get_price_excluding_tax( $fresh );
            }
        }

        // Prices stored WITHOUT tax in WooCommerce — use as-is
        return round( $raw_price, 4 );
    }

    public static function effective_margin( \WC_Product $product ): float {
        $id     = $product->get_id();
        $margin = PostMeta::get_margin( $id );
        if ( null !== $margin ) {
            return $margin;
        }
        if ( $product->is_type( 'variation' ) ) {
            $parent_margin = PostMeta::get_margin( $product->get_parent_id() );
            if ( null !== $parent_margin ) {
                return $parent_margin;
            }
        }
        return Options::global_margin();
    }

    public static function effective_max_margin( \WC_Product $product ): float {
        $id  = $product->get_id();
        $val = PostMeta::get_max_margin( $id );
        if ( null !== $val ) {
            return $val;
        }
        if ( $product->is_type( 'variation' ) ) {
            $parent_val = PostMeta::get_max_margin( $product->get_parent_id() );
            if ( null !== $parent_val ) {
                return $parent_val;
            }
        }
        return Options::global_max_margin();
    }

    /**
     * Effective min margin % — cascade: variation → parent → global.
     * If no custom min margin set anywhere, mirrors effective_margin().
     */
    public static function effective_min_margin( \WC_Product $product ): float {
        $id  = $product->get_id();
        $val = PostMeta::get_min_margin( $id );
        if ( null !== $val ) {
            return $val;
        }
        if ( $product->is_type( 'variation' ) ) {
            $parent_val = PostMeta::get_min_margin( $product->get_parent_id() );
            if ( null !== $parent_val ) {
                return $parent_val;
            }
        }
        return Options::global_min_margin();
    }

    /**
     * Check if computed price is below the minimum allowed price.
     * Returns true → block sync.
     *
     * Min price = source_price × (1 + min_margin/100)
     */
    public static function is_below_min_margin( \WC_Product $product ): bool {
        $source = self::source_price( $product );
        if ( null === $source || $source <= 0 ) {
            return false;
        }
        $computed    = self::computed_price( $product );
        if ( null === $computed ) {
            return false;
        }
        $min_margin  = self::effective_min_margin( $product );
        $min_allowed = $source * ( 1 + $min_margin / 100 );
        return $computed < $min_allowed;
    }

    public static function apply_rounding( float $price ): float {
        switch ( Options::rounding_rule() ) {
            case '2decimals':
                return round( $price, 2 );
            case 'end99':
                return floor( $price ) + 0.99;
            default:
                return round( $price, 4 );
        }
    }

    // ── Stock ─────────────────────────────────────────────────────────────

    /**
     * Compute eMAG stock quantity.
     *
     * Formula: ceil( wc_stock × stock_pct / 100 )
     * Returns null  → skip sync (wc_stock = 0 or not managed)
     * Returns 0     → send stock=0 to eMAG (stock_pct=0 or below min threshold)
     * Returns int≥1 → send to eMAG
     */
    public static function computed_stock( \WC_Product $product ): ?int {
        $wc_qty = (int) $product->get_stock_quantity();

        if ( $wc_qty <= 0 ) {
            return null; // skip — out of stock in WC
        }

        // If WC stock is at or below the minimum threshold, send 0 to eMAG
        $min_stock = Options::min_wc_stock();
        if ( $min_stock > 0 && $wc_qty <= $min_stock ) {
            return 0; // treat as out of stock on eMAG
        }

        $pct  = self::effective_stock_percent( $product );

        // Stock % = 0 means "send zero stock to eMAG" (hide product without deactivating)
        if ( $pct <= 0.0 ) {
            return 0;
        }

        $emag = (int) ceil( $wc_qty * $pct / 100 );

        return max( 1, min( $emag, self::MAX_STOCK ) );
    }

    public static function effective_stock_percent( \WC_Product $product ): float {
        $id  = $product->get_id();
        $pct = PostMeta::get_stock_percent( $id );
        if ( null !== $pct ) {
            return $pct;
        }
        if ( $product->is_type( 'variation' ) ) {
            $parent_pct = PostMeta::get_stock_percent( $product->get_parent_id() );
            if ( null !== $parent_pct ) {
                return $parent_pct;
            }
        }
        return Options::global_stock_percent();
    }

    // ── Status ────────────────────────────────────────────────────────────

    /**
     * Get effective eMAG status for a product.
     *
     * Returns 0 if the product has been marked inactive locally,
     * otherwise returns 1 (active).
     */
    public static function effective_emag_status( \WC_Product $product ): int {
        $stored = get_post_meta( $product->get_id(), PostMeta::EMAG_STATUS, true );
        // If explicitly set to 0, respect it.
        if ( $stored !== '' && $stored !== false && (int) $stored === 0 ) {
            return 0;
        }
        return 1;
    }
}
