<commit_before><?php

/*
 * This file is part of the Search PHP Library.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * Feel free to edit as you please, and have fun.
 *
 * @author <NAME> <<EMAIL>>
 * @author PuntMig Technologies
 */

declare(strict_types=1);

namespace Puntmig\Search\Model;

use DateTime;

/**
 * Class Product.
 */
class Product implements HttpTransportable
{
    /**
     * @var string
     *
     * Name
     */
    const TYPE = 'product';

    /**
     * @var ProductReference
     *
     * Product reference
     */
    private $productReference;

    /**
     * @var string
     *
     * EAN
     */
    private $ean;

    /**
     * @var string
     *
     * Name
     */
    private $name;

    /**
     * @var string
     *
     * Slug
     */
    private $slug;

    /**
     * @var string
     *
     * Description
     */
    private $description;

    /**
     * @var string
     *
     * Long description
     */
    private $longDescription;

    /**
     * @var int
     *
     * price
     */
    private $price;

    /**
     * @var int
     *
     * Reduced price
     */
    private $reducedPrice;

    /**
     * @var string
     *
     * Currency
     */
    private $currency;

    /**
     * @var int
     *
     * Stock
     */
    private $stock;

    /**
     * @var Manufacturer[]
     *
     * ManufacturerS
     */
    private $manufacturers;

    /**
     * @var Brand
     *
     * Brand
     */
    private $brand;

    /**
     * @var Category[]
     *
     * Categories
     */
    private $categories;

    /**
     * @var Tag[]
     *
     * Tags
     */
    private $tags;

    /**
     * @var string
     *
     * Image
     */
    private $image;

    /**
     * @var float
     *
     * Rating
     */
    private $rating;

    /**
     * @var Coordinate
     *
     * Coordinate
     */
    private $coordinate;

    /**
     * @var float
     *
     * Distance
     */
    private $distance;

    /**
     * @var string[]
     *
     * Stores
     */
    private $stores;

    /**
     * @var string
     *
     * First level searchable data
     */
    private $firstLevelSearchableData;

    /**
     * @var string
     *
     * Second level searchable data
     */
    private $secondLevelSearchableData;

    /**
     * @var DateTime
     *
     * Updated at
     */
    private $updatedAt;

    /**
     * @var array
     *
     * Metadata
     */
    private $metadata;

    /**
     * @var array
     *
     * Indexed Metadata
     */
    private $indexedMetadata;

    /**
     * @var array
     *
     * Special words
     */
    private $specialWords = [];

    /**
     * @var int
     *
     * Extra boost
     */
    private $extraBoost;

    /**
     * Product constructor.
     *
     * @param string          $id
     * @param string          $family
     * @param string          $ean
     * @param string          $name
     * @param string          $slug
     * @param string          $description
     * @param null|string     $longDescription
     * @param float           $price
     * @param string          $currency
     * @param null|float      $reducedPrice
     * @param null|int        $stock
     * @param null|Brand      $brand
     * @param null|string     $image
     * @param null|float      $rating
     * @param null|DateTime   $updatedAt
     * @param null|Coordinate $coordinate
     * @param array           $stores
     * @param array           $metadata
     * @param array           $indexedMetadata
     * @param array           $specialWords
     * @param int             $extraBoost
     */
    public function __construct(
        string $id,
        string $family,
        string $ean,
        string $name,
        string $slug,
        string $description,
        ? string $longDescription,
        float $price,
        ? float $reducedPrice,
        string $currency,
        ? int $stock = null,
        ? Brand $brand = null,
        ? string $image = null,
        ? float $rating = null,
        ? DateTime $updatedAt = null,
        ? Coordinate $coordinate = null,
        array $stores = [],
        array $indexedMetadata = [],
        array $metadata = [],
        array $specialWords = [],
        int $extraBoost = 0
    ) {
        $this->productReference = new ProductReference($id, $family);
        $this->ean = $ean;
        $this->name = $name;
        $this->slug = $slug;
        $this->description = $description;
        $this->longDescription = $longDescription;
        $this->price = $price;
        $this->reducedPrice = $reducedPrice;
        $this->currency = $currency;
        $this->stock = $stock;
        $this->manufacturers = [];
        $this->brand = $brand;
        $this->categories = [];
        $this->tags = [];
        $this->image = $image;
        $this->rating = $rating;
        $this->updatedAt = $updatedAt;
        $this->coordinate = $coordinate;
        $this->stores = $stores;
        $this->indexedMetadata = $indexedMetadata;
        $this->metadata = $metadata;
        $this->setSpecialWords($specialWords);
        $this->extraBoost = $extraBoost;

        $this->recalculateRelativeValues();
    }

    /**
     * Recalculate relative values from current local parameters.
     *
     * This method should not have external class effects
     */
    public function recalculateRelativeValues()
    {
        $this->longDescription = ($this->longDescription ?? '');
        $this->image = ($this->image ?? '');

        /**
         * Predefined indexed metadata.
         */
        $this->indexedMetadata['with_image'] = (empty($this->image)) ? '0' : '1';
        $this->indexedMetadata['with_discount'] = ($this->getDiscountPercentage() > 0) ? '1' : '0';
        $this->indexedMetadata['with_stock'] = ($this->getStock() > 0) ? '1' : '0';

        $this->rating = !is_null($this->rating)
            ? round($this->rating, 1)
            : null;

        $this->updatedAt = ($this->updatedAt ?? new DateTime());

        $this->firstLevelSearchableData = $this->name;
        $this->secondLevelSearchableData = "$this->description $this->longDescription";

        if ($this->brand instanceof Brand) {
            $this->firstLevelSearchableData .= " {$this->brand->getName()}";
        }

        foreach ($this->tags as $tag) {
            $this->firstLevelSearchableData .= " {$tag->getName()}";
        }

        foreach ($this->categories as $category) {
            $this->firstLevelSearchableData .= " {$category->getName()}";
        }

        foreach ($this->manufacturers as $manufacturer) {
            $this->firstLevelSearchableData .= " {$manufacturer->getName()}";
        }
    }

    /**
     * Get product reference.
     *
     * @return ProductReference
     */
    public function getProductReference()
    {
        return $this->productReference;
    }

    /**
     * Get product id.
     *
     * @return string
     */
    public function getId() : string
    {
        return $this
            ->productReference
            ->getId();
    }

    /**
     * Get family.
     *
     * @return string
     */
    public function getFamily() : string
    {
        return $this
            ->productReference
            ->getFamily();
    }

    /**
     * Get EAN.
     *
     * @return string
     */
    public function getEan() : string
    {
        return $this->ean;
    }

    /**
     * Set name.
     *
     * @param string $name
     */
    public function setName(string $name)
    {
        $this->name = $name;
    }

    /**
     * Get name.
     *
     * @return string
     */
    public function getName() : string
    {
        return $this->name;
    }

    /**
     * Set slug.
     *
     * @param string $slug
     */
    public function setSlug(string $slug)
    {
        $this->slug = $slug;
        $this->recalculateRelativeValues();
    }

    /**
     * Get slug.
     *
     * @return string
     */
    public function getSlug() : string
    {
        return $this->slug;
    }

    /**
     * Set description.
     *
     * @param string $description
     */
    public function setDescription(string $description)
    {
        $this->description = $description;
        $this->recalculateRelativeValues();
    }

    /**
     * Get description.
     *
     * @return string
     */
    public function getDescription() : string
    {
        return $this->description;
    }

    /**
     * Set long description.
     *
     * @param null|string $longDescription
     */
    public function setLongDescription(? string $longDescription)
    {
        $this->longDescription = $longDescription;
        $this->recalculateRelativeValues();
    }

    /**
     * Get long description.
     *
     * @return string
     */
    public function getLongDescription() : string
    {
        return $this->longDescription;
    }

    /**
     * Set price.
     *
     * @param float $price
     */
    public function setPrice(float $price)
    {
        $this->price = $price;
        $this->recalculateRelativeValues();
    }

    /**
     * Get price.
     *
     * @return float
     */
    public function getPrice() : float
    {
        return $this->price;
    }

    /**
     * Set reduced price.
     *
     * @param null|float $reducedPrice
     */
    public function setReducedPrice(? float $reducedPrice)
    {
        $this->reducedPrice = $reducedPrice;
        $this->recalculateRelativeValues();
    }

    /**
     * Get reduced price.
     *
     * @return null|float
     */
    public function getReducedPrice() : ? float
    {
        return $this->reducedPrice;
    }

    /**
     * Get real price.
     *
     * @return float
     */
    public function getRealPrice() : float
    {
        return min(
            $this->price,
            $this->reducedPrice ?? $this->price
        );
    }

    /**
     * Get discount.
     *
     * @return float
     */
    public function getDiscount() : float
    {
        return $this->price - $this->getRealPrice();
    }

    /**
     * Get discount percentage.
     *
     * @return int
     */
    public function getDiscountPercentage() : int
    {<commit_msg>Fixed when price is 0<commit_after><?php

/*
 * This file is part of the Search PHP Library.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * Feel free to edit as you please, and have fun.
 *
 * @author <NAME> <<EMAIL>>
 * @author PuntMig Technologies
 */

declare(strict_types=1);

namespace Puntmig\Search\Model;

use DateTime;

/**
 * Class Product.
 */
class Product implements HttpTransportable
{
    /**
     * @var string
     *
     * Name
     */
    const TYPE = 'product';

    /**
     * @var ProductReference
     *
     * Product reference
     */
    private $productReference;

    /**
     * @var string
     *
     * EAN
     */
    private $ean;

    /**
     * @var string
     *
     * Name
     */
    private $name;

    /**
     * @var string
     *
     * Slug
     */
    private $slug;

    /**
     * @var string
     *
     * Description
     */
    private $description;

    /**
     * @var string
     *
     * Long description
     */
    private $longDescription;

    /**
     * @var int
     *
     * price
     */
    private $price;

    /**
     * @var int
     *
     * Reduced price
     */
    private $reducedPrice;

    /**
     * @var string
     *
     * Currency
     */
    private $currency;

    /**
     * @var int
     *
     * Stock
     */
    private $stock;

    /**
     * @var Manufacturer[]
     *
     * ManufacturerS
     */
    private $manufacturers;

    /**
     * @var Brand
     *
     * Brand
     */
    private $brand;

    /**
     * @var Category[]
     *
     * Categories
     */
    private $categories;

    /**
     * @var Tag[]
     *
     * Tags
     */
    private $tags;

    /**
     * @var string
     *
     * Image
     */
    private $image;

    /**
     * @var float
     *
     * Rating
     */
    private $rating;

    /**
     * @var Coordinate
     *
     * Coordinate
     */
    private $coordinate;

    /**
     * @var float
     *
     * Distance
     */
    private $distance;

    /**
     * @var string[]
     *
     * Stores
     */
    private $stores;

    /**
     * @var string
     *
     * First level searchable data
     */
    private $firstLevelSearchableData;

    /**
     * @var string
     *
     * Second level searchable data
     */
    private $secondLevelSearchableData;

    /**
     * @var DateTime
     *
     * Updated at
     */
    private $updatedAt;

    /**
     * @var array
     *
     * Metadata
     */
    private $metadata;

    /**
     * @var array
     *
     * Indexed Metadata
     */
    private $indexedMetadata;

    /**
     * @var array
     *
     * Special words
     */
    private $specialWords = [];

    /**
     * @var int
     *
     * Extra boost
     */
    private $extraBoost;

    /**
     * Product constructor.
     *
     * @param string          $id
     * @param string          $family
     * @param string          $ean
     * @param string          $name
     * @param string          $slug
     * @param string          $description
     * @param null|string     $longDescription
     * @param float           $price
     * @param string          $currency
     * @param null|float      $reducedPrice
     * @param null|int        $stock
     * @param null|Brand      $brand
     * @param null|string     $image
     * @param null|float      $rating
     * @param null|DateTime   $updatedAt
     * @param null|Coordinate $coordinate
     * @param array           $stores
     * @param array           $metadata
     * @param array           $indexedMetadata
     * @param array           $specialWords
     * @param int             $extraBoost
     */
    public function __construct(
        string $id,
        string $family,
        string $ean,
        string $name,
        string $slug,
        string $description,
        ? string $longDescription,
        float $price,
        ? float $reducedPrice,
        string $currency,
        ? int $stock = null,
        ? Brand $brand = null,
        ? string $image = null,
        ? float $rating = null,
        ? DateTime $updatedAt = null,
        ? Coordinate $coordinate = null,
        array $stores = [],
        array $indexedMetadata = [],
        array $metadata = [],
        array $specialWords = [],
        int $extraBoost = 0
    ) {
        $this->productReference = new ProductReference($id, $family);
        $this->ean = $ean;
        $this->name = $name;
        $this->slug = $slug;
        $this->description = $description;
        $this->longDescription = $longDescription;
        $this->price = $price;
        $this->reducedPrice = $reducedPrice;
        $this->currency = $currency;
        $this->stock = $stock;
        $this->manufacturers = [];
        $this->brand = $brand;
        $this->categories = [];
        $this->tags = [];
        $this->image = $image;
        $this->rating = $rating;
        $this->updatedAt = $updatedAt;
        $this->coordinate = $coordinate;
        $this->stores = $stores;
        $this->indexedMetadata = $indexedMetadata;
        $this->metadata = $metadata;
        $this->setSpecialWords($specialWords);
        $this->extraBoost = $extraBoost;

        $this->recalculateRelativeValues();
    }

    /**
     * Recalculate relative values from current local parameters.
     *
     * This method should not have external class effects
     */
    public function recalculateRelativeValues()
    {
        $this->longDescription = ($this->longDescription ?? '');
        $this->image = ($this->image ?? '');

        /**
         * Predefined indexed metadata.
         */
        $this->indexedMetadata['with_image'] = (empty($this->image)) ? '0' : '1';
        $this->indexedMetadata['with_discount'] = ($this->getDiscountPercentage() > 0) ? '1' : '0';
        $this->indexedMetadata['with_stock'] = ($this->getStock() > 0) ? '1' : '0';

        $this->rating = !is_null($this->rating)
            ? round($this->rating, 1)
            : null;

        $this->updatedAt = ($this->updatedAt ?? new DateTime());

        $this->firstLevelSearchableData = $this->name;
        $this->secondLevelSearchableData = "$this->description $this->longDescription";

        if ($this->brand instanceof Brand) {
            $this->firstLevelSearchableData .= " {$this->brand->getName()}";
        }

        foreach ($this->tags as $tag) {
            $this->firstLevelSearchableData .= " {$tag->getName()}";
        }

        foreach ($this->categories as $category) {
            $this->firstLevelSearchableData .= " {$category->getName()}";
        }

        foreach ($this->manufacturers as $manufacturer) {
            $this->firstLevelSearchableData .= " {$manufacturer->getName()}";
        }
    }

    /**
     * Get product reference.
     *
     * @return ProductReference
     */
    public function getProductReference()
    {
        return $this->productReference;
    }

    /**
     * Get product id.
     *
     * @return string
     */
    public function getId() : string
    {
        return $this
            ->productReference
            ->getId();
    }

    /**
     * Get family.
     *
     * @return string
     */
    public function getFamily() : string
    {
        return $this
            ->productReference
            ->getFamily();
    }

    /**
     * Get EAN.
     *
     * @return string
     */
    public function getEan() : string
    {
        return $this->ean;
    }

    /**
     * Set name.
     *
     * @param string $name
     */
    public function setName(string $name)
    {
        $this->name = $name;
    }

    /**
     * Get name.
     *
     * @return string
     */
    public function getName() : string
    {
        return $this->name;
    }

    /**
     * Set slug.
     *
     * @param string $slug
     */
    public function setSlug(string $slug)
    {
        $this->slug = $slug;
        $this->recalculateRelativeValues();
    }

    /**
     * Get slug.
     *
     * @return string
     */
    public function getSlug() : string
    {
        return $this->slug;
    }

    /**
     * Set description.
     *
     * @param string $description
     */
    public function setDescription(string $description)
    {
        $this->description = $description;
        $this->recalculateRelativeValues();
    }

    /**
     * Get description.
     *
     * @return string
     */
    public function getDescription() : string
    {
        return $this->description;
    }

    /**
     * Set long description.
     *
     * @param null|string $longDescription
     */
    public function setLongDescription(? string $longDescription)
    {
        $this->longDescription = $longDescription;
        $this->recalculateRelativeValues();
    }

    /**
     * Get long description.
     *
     * @return string
     */
    public function getLongDescription() : string
    {
        return $this->longDescription;
    }

    /**
     * Set price.
     *
     * @param float $price
     */
    public function setPrice(float $price)
    {
        $this->price = $price;
        $this->recalculateRelativeValues();
    }

    /**
     * Get price.
     *
     * @return float
     */
    public function getPrice() : float
    {
        return $this->price;
    }

    /**
     * Set reduced price.
     *
     * @param null|float $reducedPrice
     */
    public function setReducedPrice(? float $reducedPrice)
    {
        $this->reducedPrice = $reducedPrice;
        $this->recalculateRelativeValues();
    }

    /**
     * Get reduced price.
     *
     * @return null|float
     */
    public function getReducedPrice() : ? float
    {
        return $this->reducedPrice;
    }

    /**
     * Get real price.
     *
     * @return float
     */
    public function getRealPrice() : float
    {
        return min(
            $this->price,
            $this->reducedPrice ?? $this->price
        );
    }

    /**
     * Get discount.
     *
     * @return float
     */
    public function getDiscount() : float
    {
        return $this->price - $this->getRealPrice();
    }

    /**
     * Get discount percentage.
     *
     * @return int
     */
    public function getDiscountPercentage() : int
    {
        if ($this->getPrice() == 0) {
            return 0;
        }

{'fraction_non_alphanumeric': 0.13242652416808356, 'fraction_numerical': 0.0012144765606023804, 'mean_word_length': 1.5544112172726146, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 184, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2800228', 'n_tokens_mistral': 6118, 'n_tokens_neox': 5938, 'n_words': 1329}