<?php

namespace objects;

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

class categories_o extends db
{
    use db_object_t;

    public object_property $name;
    public object_property $description;

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

    /**
     * @param string $name
     * @param string $description
     * @throws Exception If the object is not selected, it throws an exception
     */
    public function add(string $name, string $description): void
    {
        global /** @var db $db */
        $db;
        // Avoid SQL injection
        $name = $db->escape_string($name);
        $description = $db->escape_string($description);
        $tmp_id = self::add_object([
            'name' => $name,
            'description' => $description
        ]);

        // Transfer the temporary id to the current object
        $this->id = $tmp_id;

        // Set the values of the object properties
        $this->getObjectProperties();

        // Trigger the object changed event
        self::objectChanged();
    }

    public function getObjectProperties(): void
    {
        $this->name = new object_property($this->table, $this->id, 'name', 'string', true);
        $this->description = new object_property($this->table, $this->id, 'description', 'string', false);
    }

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

    /**
     * Set the description of the category
     * @throws Exception If the object is not selected, it throws an exception
     */
    public function set_description(string $description): self
    {
        self::requireSelected();
        $this->description->set($description);
        self::objectChanged();
        return $this;
    }

    /**
     * Set the name of the category
     * @throws Exception If the object is not selected, it throws an exception
     */
    public function set_name(string $name): self
    {
        self::requireSelected();
        $this->name->set($name);
        self::objectChanged();
        return $this;
    }

    public function asArray(): array
    {
        $products = (new products_o())->getFieldsWhere(['category' => $this->id], ['id']);
        $products = array_map(function ($product) {
            return (int)$product['id'];
        }, $products);
        return [
            'id' => (int)$this->id,
            'name' => (string)$this->name,
            'description' => (string)$this->description,
            'meta' => [
                'products' => (array)$products,
                'product_count' => (int)count($products),
            ]
        ];
    }

    /**
     * @return products_o[] An array of products in this category
     * @throws Exception If the object is not selected, it throws an exception
     */
    public function getProducts(): array
    {
        self::requireSelected();
        $products_data = (new products_o())->getFieldsWhere(['category' => $this->id], ['id']);
        /** @var products_o[] $products */
        $products = [];
        foreach ($products_data as $product_data) {
            $product = new products_o();
            $product->select((int)$product_data['id']);
            $products[] = $product;
        }
        return $products;
    }
}