<?php

namespace objects;

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

class groups_o extends db
{
    use db_object_t;

    public object_property $name;
    public object_property $description;
    public object_property $created_at;


    public function structure(): void
    {
        self::setTable('groups');
    }

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

    /**
     * Get all permissions for a group
     * @return array
     * @throws Exception If the group was not selected
     */
    public function getPermissions(): array
    {
        self::requireSelected();
        return (new groups_permissions_o())->getGroupPermissions($this->id);
    }

    /**
     * Get department ids, that the group has permission (department_access_:group_id) to access
     * @return array An array of department ids e.g. [1, 2, 3]
     * @throws Exception If the group was not selected
     */
    public function getDepartments(): array
    {
        if (!$this->exists()) {
            return [];
        }
        $permissions = (new groups_permissions_o())->getGroupPermissionsMatching($this->id, '/^department_access_[0-9]+$/');
        $departments = [];
        foreach ( $permissions as $value ) {
            $tmp = explode('_', $value['permission']);
            $departments[] = (int)$tmp[2];
        }
        return $departments;
    }

    /**
     * Remove a permission from a group
     *
     * @param string $permission_id
     * @return self $this
     * @throws Exception If the permission was not removed successfully
     */
    public function removePermission(string $permission_id): self
    {
        self::requireSelected();
        (new groups_permissions_o())->remove($this->id, $permission_id);
        return $this;
    }

    /**
     * Clone a group with all its permissions
     * @param string $name
     * @param string $description
     * @return void
     * @throws Exception
     */
    public function clone(string $name, string $description): void
    {
        self::requireSelected();
        $group = new groups_o();
        $group->add($name, $description);
        $permissions = (new groups_permissions_o())->getGroupPermissions($this->id);
        foreach ( $permissions as $permission ) {
            $group->addPermission($permission);
        }
    }

    /**
     * Add a group
     * @param string $name
     * @param string $description
     * @return void
     * @throws Exception If the object was not created successfully
     */
    public function add(string $name, string $description): void
    {
        $tmp_id = self::add_object([
            'name' => $name,
            'description' => $description
        ]);
        $this->id = $tmp_id;
        self::getObjectProperties();
        self::objectChanged();
        if (!$this->id) {
            throw new Exception('The group was not created successfully.');
        }
    }

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

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

    /**
     * Add a permission to a group
     *
     * @param string $permission_id
     * @return self $this
     * @throws Exception If the permission was not added successfully
     */
    public function addPermission(string $permission_id): self
    {
        self::requireSelected();
        (new groups_permissions_o())->add($this->id, $permission_id);
        return $this;
    }

    public function getDepartmentsScannerNames(): array
    {
        self::requireSelected();
        $departments = $this->getDepartments();
        $plate_scanners_o = new plate_scanners_o();
        $tmp = $plate_scanners_o->getFieldsWhere(['department_id' => $departments], ['id', 'name']);
        return array_map(
            function ($scanner) {
                return $scanner['name'];
            },
            $tmp
        );
    }

    public function getDepartmentsScannersHallIds(): array
    {
        self::requireSelected();
        $departments = $this->getDepartments();
        $plate_scanners_o = new plate_scanners_o();
        $tmp = $plate_scanners_o->getFieldsWhere([
            'department_id' => $departments,
            'HallId' => '!null'
        ], ['id', 'HallId']);
        return array_map(
            function ($scanner) {
                return (string)$scanner['HallId'];
            },
            $tmp
        );
    }
}