<?php
namespace Pay4All\Pro\Frontend;

use Pay4All\Pro\PostTypes;
use Pay4All\Pro\Domain\Category;
use Pay4All\Pro\Domain\Brand;
use Pay4All\Pro\License\LicenseManager;

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

/**
 * Server-side backstop for the category + brand quantity rules that the
 * client-side validator in form.js enforces at the last-but-one form step.
 * The JS check gates the « Suivant » button, but a payload crafted by a
 * malicious or misbehaving client (curl script, custom app, JS-off browser
 * ignoring the fetch guards) would otherwise slip past it and land a real
 * order that violates the rule tree the merchant configured.
 *
 * Runtime :
 *
 *   1. pay4all-form's Frontend\Submission fires
 *      `apply_filters( 'p4all_form_cart_rule_errors', [], $items, $form_id )`
 *      after Validator::validate() has produced the sanitised item bag.
 *   2. We tally quantities per category id + per brand id (a product in
 *      several terms counts against each — same shape the JS uses via
 *      the `cats` / `brands` arrays we inject in Integrations\Pay4AllForm).
 *   3. For each term that carries a `rule_type` different from `none`
 *      we call the domain helpers Category::validate_category() /
 *      Brand::validate_brand() which return either the merchant's custom
 *      error message or a localised default.
 *   4. Non-empty error strings are collected and returned as the filter
 *      value ; Submission then short-circuits with wp_send_json_error()
 *      and the client renders the errors under the products step.
 *
 * The whole class is a silent no-op when the licence is inactive (the
 * client-side rules already disappear when Pay4All Pro is turned off, so
 * the server-side backstop follows the same gating).
 */
final class CartRuleValidator {

	public static function register() : void {
		add_filter( 'p4all_form_cart_rule_errors', [ self::class, 'validate_cart' ], 10, 3 );
	}

	/**
	 * @param array<string> $errors
	 * @param array<int,array{product_id:int,qty:int}> $items
	 * @param int           $form_id
	 * @return array<string>
	 */
	public static function validate_cart( array $errors, array $items, int $form_id ) : array {
		if ( ! LicenseManager::is_feature_allowed() ) { return $errors; }
		if ( empty( $items ) ) { return $errors; }

		$cat_totals   = [];
		$brand_totals = [];

		foreach ( $items as $it ) {
			$pid = (int) ( $it['product_id'] ?? 0 );
			$qty = (int) ( $it['qty']        ?? 0 );
			if ( $pid <= 0 || $qty <= 0 ) { continue; }

			$cats = array_map( 'intval', (array) wp_get_object_terms( $pid, PostTypes::TAXONOMY,       [ 'fields' => 'ids' ] ) );
			foreach ( $cats as $tid ) {
				if ( $tid <= 0 ) { continue; }
				$cat_totals[ $tid ] = ( $cat_totals[ $tid ] ?? 0 ) + $qty;
			}

			$brands = array_map( 'intval', (array) wp_get_object_terms( $pid, PostTypes::TAXONOMY_BRAND, [ 'fields' => 'ids' ] ) );
			foreach ( $brands as $tid ) {
				if ( $tid <= 0 ) { continue; }
				$brand_totals[ $tid ] = ( $brand_totals[ $tid ] ?? 0 ) + $qty;
			}
		}

		foreach ( $cat_totals as $tid => $qty ) {
			$msg = Category::validate_category( (int) $tid, (int) $qty );
			if ( $msg !== '' ) { $errors[] = $msg; }
		}
		foreach ( $brand_totals as $tid => $qty ) {
			$msg = Brand::validate_brand( (int) $tid, (int) $qty );
			if ( $msg !== '' ) { $errors[] = $msg; }
		}

		return $errors;
	}
}
