<?php

namespace objects;

use classes\db;
use classes\object_property;
use Exception;
use traits\db_object_t;

class product_options_o extends db
{
    use db_object_t;

    public object_property $product_id;
    public object_property $option_id;
    public object_property $name;
    public object_property $min;
    public object_property $max;

    public function structure(): void
    {
        $this->setTable('products_options');
    }

    /**
     * Add a product option, and set this object to the new object
     * @param int $product_id
     * @param int $option_id
     * @return void
     * @throws Exception If the object was not created successfully
     */
    public function add(int $product_id, int $option_id): void
    {
        $tmp_id = self::add_object([
            'product_id' => $product_id,
            'option_id' => $option_id
        ]);
        $this->id = $tmp_id;
        self::getObjectProperties();
        self::objectChanged();
    }

    public function getObjectProperties(): void
    {
        $this->product_id = new object_property($this->table, $this->id, 'product_id', 'int', false);
        $this->option_id = new object_property($this->table, $this->id, 'option_id', 'int', false);
        $this->name = new object_property($this->table, $this->id, 'name', 'string', false);
        $this->min = new object_property($this->table, $this->id, 'min', 'int', false);
        $this->max = new object_property($this->table, $this->id, 'max', 'int', false);
    }

    public function objectChanged(): void
    {
        //TODO: Add cache invalidation
    }

    /**
     * There's no need to keep track of when a product option is deleted,
     * so we just forcefully delete it.
     * @throws Exception If the object was not selected
     * @throws Exception If the object was not deleted successfully
     */
    public function delete(): void
    {
        self::requireSelected();
        self::deletePermanently();
    }

    /**
     * Set the name of the product option
     * @param string $name
     * @throws Exception If the object was not selected
     */
    public function set_name(string $name): void
    {
        self::requireSelected();
        // If the string is empty, set it to null
        if (empty($name)) {
            $this->name->nullify();
            self::objectChanged();
            return;
        }
        $this->name->set($name);
        self::objectChanged();
    }

    /**
     * Set the min value of the product option
     * @param int|null $min
     * @notation If the int is less than 1 or empty, set it to null
     * @throws Exception If the object was not selected
     */
    public function set_min(int|null $min): void
    {
        self::requireSelected();
        // If the int is empty, set it to null
        if (empty($min) || $min < 1) {
            $this->min->nullify();
            self::objectChanged();
            return;
        }
        $this->min->set($min);
        self::objectChanged();
    }

    /**
     * Set the max value of the product option
     * @param int|null $max
     * @notation If the int is less than 1, or empty, it will be set to null
     * @throws Exception If the object was not selected
     */
    public function set_max(int|null $max): void
    {
        self::requireSelected();
        // If the int is empty, set it to null
        if (empty($max) || $max < 1) {
            $this->max->nullify();
            self::objectChanged();
            return;
        }
        $this->max->set($max);
        self::objectChanged();
    }

    /**
     * Get all options for a product
     * @param int $id The id of the product
     * @return array
     * @throws Exception If the object was not selected
     */
    public function getProductOptions(int $id): array
    {
        $options = self::getFieldsWhere(['product_id' => $id],
            [
                'id',
                'product_id',
                'option_id',
                'name',
                'min',
                'max',
                'created_at',
                'updated_at'
            ]
        );
        $tmp = [];
        foreach ( $options as $option ) {
            $tmp_product = (new products_o())->select($option['option_id'])->asArray();
            $tmp[] = [
                'id' => (int)$option['id'],
                'product_id' => (int)$option['product_id'],
                'option_id' => (int)$option['option_id'],
                'name' => (string)$option['name'] === '' ? $tmp_product['name'] : (string)$option['name'],
                'min' => $option['min'] === null ? 0 : (int)$option['min'],
                'max' => $option['max'] === null ? -1 : (int)$option['max'],
                'created_at' => (string)$option['created_at'],
                'updated_at' => (string)$option['updated_at'],
                'price' => (int)$tmp_product['price'],
                'product' => $tmp_product
            ];
        }
        return $tmp;
    }

    /**
     * Get the product option as an array
     * @return array
     * @throws Exception If the object was not selected
     */
    public function asArray(): array
    {
        self::requireSelected();
        return [
            'id' => (int)$this->id,
            'product_id' => (int)$this->product_id->value(),
            'option_id' => (int)$this->option_id->value(),
            'name' => (string)$this->name->value(),
            'min' => $this->min->value() === null ? null : (int)$this->min->value(),
            'max' => $this->max->value() === null ? null : (int)$this->max->value()
        ];
    }

    /**
     * Get all products with a specific option
     * @param int $product_id The id of the addon product
     * @return array
     */
    public function getOptionProducts(int $product_id): array
    {
        return self::getFieldsWhere(['option_id' => $product_id], ['product_id']);
    }

    public function isOptionAllowedOnType(int $option_id, int $primary_type_id): bool
    {
        // Check if the option is allowed on the primary type
        $allowed_options = self::getFieldsWhere(
            ['option_id' => $option_id, 'product_id' => $primary_type_id],
            ['id']
        );
        return !empty($allowed_options);
    }
}