<?php
/**
 * BookiFlex Core
 *
 * @package    BookiFlex
 * @subpackage Core
 * @author     BookiFlex
 * @copyright  Copyright (c) 2025 BookiFlex
 * @license    GPL-2.0-or-later
 *
 * @link       https://bookiflex.com
 */

declare(strict_types=1);

namespace BookiFlex\Core\Model\RatePlan;

use BookiFlex\Core\Model\AccommodationType\AccommodationPlacementTypeInterface;
use BookiFlex\Core\Model\DateUnit\DateUnitTypeInterface;
use BookiFlex\Core\Model\DateUnit\InheritancePriceRulesInterface;

defined( 'ABSPATH' ) || exit;

class InheritancePriceRules implements \JsonSerializable, InheritancePriceRulesInterface
{
    protected static array $placementTypeList = [
        AccommodationPlacementTypeInterface::ADULT_ON_MAIN_PLACE,
        AccommodationPlacementTypeInterface::ADULT_ON_EXTRA_PLACE,
        AccommodationPlacementTypeInterface::CHILD_ON_MAIN_PLACE,
        AccommodationPlacementTypeInterface::CHILD_ON_EXTRA_PLACE,
        AccommodationPlacementTypeInterface::CHILD_WITHOUT_PLACE
    ];

    protected array $rules;

    /**
     * InheritanceOfPriceRules constructor.
     * @param array $rules
     *
     * $rules = [
     *   [
     *      'placementTypes' => ['adultsOnMainPlacement', 'adultsOnExtraPlacement'],
     *      'type' => DateUnitTypeInterface::FORMULA_CALCULATE_TYPE,
     *      'adjustment' => null,
     *      'value' => 'rate + 500 * beds'
     *   ],
     *   [
     *      'placementTypes' => ['adultsOnExtraPlacement'],
     *      'type' => DateUnitTypeInterface::PERCENT_CALCULATE_TYPE,
     *      'adjustment' => DateUnitTypeInterface::ADDITION_ADJUSTMENT_TYPE,
     *      'value' => 10
     *   ]
     * ]
     */
    public function __construct(array $rules)
    {
        $this->rules = [];

        foreach ($rules as $rule) {
            $rule['placementTypes'] = array_values(array_filter($rule['placementTypes'], static function ($type) {
                return in_array($type, self::$placementTypeList, true);
            }));

            if ($this->check($rule)) {
                $this->rules[] = [
                    'placementTypes' => $rule['placementTypes'],
                    'type'           => $rule['type'],
                    'adjustment'     => $rule['adjustment'],
                    'value'          => $rule['value']
                ];
            }
        }
    }

    protected function check($rule): bool
    {
        if (empty($rule['placementTypes'])) {
            return false;
        }

        if (!in_array($rule['type'], [
            DateUnitTypeInterface::FORMULA_CALCULATOR,
            DateUnitTypeInterface::PERCENTAGE_CALCULATOR,
            DateUnitTypeInterface::FIXED_CALCULATOR
        ], true)) {
            return false;
        }

        if ($rule['type'] !== DateUnitTypeInterface::FORMULA_CALCULATOR) {
            if (!in_array($rule['adjustment'], [DateUnitTypeInterface::DISCOUNT_ADJUSTMENT_TYPE, DateUnitTypeInterface::ADDITION_ADJUSTMENT_TYPE], true)) {
                return false;
            }

            if (!is_integer($rule['value']) || $rule['value'] < 0) {
                return false;
            }

            if ($rule['type'] === DateUnitTypeInterface::PERCENTAGE_CALCULATOR && $rule['value'] > 100) {
                return false;
            }
        }

        return true;
    }

    /**
     * Return modifiers for inheritance of price
     *
     * Returns an associative array where each key is a placement type,
     * and the value is an array containing modifier details.
     *
     * @return array<string, array{
     *     placementType: string,
     *     type: string,
     *     adjustment: string|null,
     *     value: int|string
     * }>
     *
     * Array structure:
     * [
     *     'placementType' => [
     *         'placementType' => string,       // One of: adultOnMainPlace, adultOnExtraPlace,
     *                                          //         childOnMainPlace, childOnExtraPlace, childWithoutPlace
     *         'type'          => string,       // Calculator type: 'formula', 'percentage', or 'fixed'
     *         'adjustment'    => string|null,  // Adjustment type: 'discount', 'addition', or null (for formula)
     *         'value'         => int|string    // Numeric value (for percentage/fixed) or formula string
     *     ],
     *     ...
     * ]
     *
     * Example:
     * [
     *     'adultOnMainPlace' => [
     *         'placementType' => 'adultOnMainPlace',
     *         'type'          => 'formula',
     *         'adjustment'    => null,
     *         'value'         => 'rate + 500 * beds'
     *     ],
     *     'adultOnExtraPlace' => [
     *         'placementType' => 'adultOnExtraPlace',
     *         'type'          => 'percentage',
     *         'adjustment'    => 'addition',
     *         'value'         => 10
     *     ]
     * ]
     */
    public function getModifiers(): array
    {
        $result = [];

        foreach ($this->rules as $rule) {
            foreach ($rule['placementTypes'] as $placementType) {
                $result[$placementType] = [
                    'placementType' => $placementType,
                    'type'          => $rule['type'],
                    'adjustment'    => $rule['adjustment'],
                    'value'         => $rule['value']
                ];
            }
        }

        return $result;
    }

    #[\ReturnTypeWillChange]
    public function jsonSerialize()
    {
        return $this->rules;
    }
}
