<?php

namespace objects;

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

class department_variables_o extends db
{
    use db_object_t;

    public int $department_id;

    public object_property $variable;
    public object_property $value;
    public object_property $created_at;

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

    /**
     * Set a department variable
     * @param string $variable The variable name
     * @param string $value The variable value
     * @return void
     *
     * @throws Exception If the object was not created successfully
     */
    public function set(string $variable, mixed $value): void
    {
        self::requireDepartmentId();
        // Check if the variable already exists
        $isAlreadyDefinedId = self::getFieldsWhere([
            'department_id' => $this->department_id,
            'variable' => $variable
        ], ['id']);
        // Update the variable if it already exists
        if ($isAlreadyDefinedId) {
            $this->id = $isAlreadyDefinedId[0]['id'];
            $this->getObjectProperties();
            $this->value->set($value);
            return;
        }
        // Add the variable
        $tmp_id = self::add_object([
            'department_id' => $this->department_id,
            'variable' => $variable,
            'value' => $value
        ]);
        $this->id = $tmp_id;
        self::getObjectProperties();
        self::objectChanged();
        if (!$this->id) {
            throw new Exception('The variable was not created successfully.');
        }
    }

    /**
     * Require the department ID to be set, and throw an exception if it is not
     * @throws Exception If the department ID is not set.
     */
    public function requireDepartmentId(): void
    {
        if (!$this->department_id) {
            throw new Exception('The department ID is not set.');
        }
    }

    /**
     * Get the department variable by ID
     * @throws Exception  If the department ID is not set
     */
    public function getObjectProperties(): void
    {
        self::requireDepartmentId();
        $this->variable = new object_property($this->table, $this->id, 'variable', 'string', false);
        $this->value = new object_property($this->table, $this->id, 'value', 'string', false);
        $this->created_at = new object_property($this->table, $this->id, 'created_at', 'string', false);
    }

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

    /**
     * List all department variables
     * @throws Exception If the department ID is not set
     */
    public function list(): array
    {
        self::requireDepartmentId();
        $variables = self::getFieldsWhere([
            'department_id' => $this->department_id
        ], ['id']);
        $result = [];
        foreach ( $variables as $variable ) {
            $tmp = new department_variables_o();
            $tmp->select($variable['id']);
            $result[] = $tmp->asArray();
        }
        return $result;
    }

    /**
     * Get the department variable by name
     * @throws Exception If the object was not selected
     */
    public function asArray(): array
    {
        self::requireSelected();
        return [
            'id' => (int)$this->id,
            'department_id' => (int)$this->department_id,
            'variable' => (string)$this->variable->value(),
            'value' => (string)$this->value->value(),
            'created_at' => (string)$this->created_at->value(),
        ];
    }

    /**
     * Get a department variable
     * @param string $variable The variable name
     * @return null If the variable is not set
     * @return mixed The variable value
     * @throws Exception If the department ID is not set
     */
    public function getVariable(string $variable): mixed
    {
        self::requireDepartmentId();
        $variable = self::getFieldsWhere([
            'department_id' => $this->department_id,
            'variable' => $variable
        ], ['value']);
        if (!$variable) {
            return null;
        }
        // Check if the variable is 'false' or 'true'
        if ($variable[0]['value'] === 'false') {
            return false;
        }
        if ($variable[0]['value'] === 'true') {
            return true;
        }
        return $variable[0]['value'];
    }

    /**
     * Check if a department variable is set
     * @param string $variable The variable name
     * @return bool If the variable is set
     * @throws Exception If the department ID is not set
     */
    public function isSet(string $variable): bool
    {
        self::requireDepartmentId();
        $variable = self::getFieldsWhere([
            'department_id' => $this->department_id,
            'variable' => $variable
        ], ['id']);
        return (bool)count($variable);
    }

    /**
     * Nullify a department variable
     * @param string $variable The variable name
     * @return void If the variable was nullified
     * @throws Exception If the object was not selected
     * @throws Exception If the department ID is not set
     */
    public function nullify(string $variable): void
    {
        self::requireDepartmentId();
        $variable = self::getFieldsWhere([
            'department_id' => $this->department_id,
            'variable' => $variable
        ], ['id']);
        if ($variable) {
            $tmp = new department_variables_o();
            $tmp->select($variable[0]['id']);
            $tmp->requireSelected();
            $tmp->delete();
        }
    }

    /**
     * Select a department
     * @param int $id The department ID
     * @return self
     */
    public function selectDepartment(int $id): self
    {
        $this->department_id = $id;
        return $this;
    }

}