<?php

namespace routes;

use classes\department_gate_config;
use classes\department_relay_config;
use classes\authentication;
use classes\response;
use objects\department_gates_o;
use objects\department_relays_o;
use objects\departments_o;
use objects\logs_o;
use traits\route_t;

class departmentGatesRelaysRoute
{
    use route_t;

    public function run(): void
    {
        $this->get('/department/gates', function () {
            global /** @var response $response */ $response;
            $this->requirePermission('list_department_gates');
            $user = (new authentication())->get_user();

            if (!$user) {
                $response->error('Invalid session', 400);
            }

            $gates_o = new department_gates_o();

            if (self::isParametersSet(['id'])) {
                self::requireType(self::getParameter('id'), self::type_int());
                self::requireMinValue((int)self::getParameter('id'), 1);
                $gate = (new department_gates_o())->select((int)self::getParameter('id'));
                if (!$gate->exists()) {
                    $response->error('Department gate not found', 404);
                }
                self::requireDepartmentAccess((int)$gate->department->value());
                $response->success($gate->asArray());
            }

            $result = $gates_o->listObjectsWithPaginationIfSet(
                function ($tmp_object_array) {
                    return (new department_gates_o())->select((int)$tmp_object_array['id'])->asArray();
                },
                $gates_o->forceRestrictFilters([
                    'department' => $user->getGroup()->getDepartments(),
                ])
            );

            (new logs_o())->add('department_gates', 'global', 1, $user->id, 'LIST_DEPARTMENT_GATES', 'User listed department gates');
            $response->success($result);
        }, [
            'list_department_gates' => 'List department gates in departments the user has access to',
        ]);

        $this->post('/department/gates', function () {
            global /** @var response $response */ $response;
            $this->requirePermission('add_department_gate');
            $user = (new authentication())->get_user();

            if (!$user) {
                $response->error('Invalid session', 400);
            }

            self::requireParameters(['department', 'is_entrance', 'is_exit', 'name', 'config']);
            self::requireType(self::getParameter('department'), self::type_int());
            self::requireMinValue((int)self::getParameter('department'), 1);
            self::requireType(self::getParameter('is_entrance'), self::type_bool());
            self::requireType(self::getParameter('is_exit'), self::type_bool());
            self::requireType(self::getParameter('name'), self::type_string());
            self::requireTypeIn(self::getParameter('config'), ['array', 'object']);
            self::requireDepartmentAccess((int)self::getParameter('department'));

            $department = (new departments_o())->select((int)self::getParameter('department'));
            if (!$department->exists()) {
                $response->error('Department not found', 404);
            }

            $config = self::getParameter('config');
            $config = is_array($config) ? $config : (array)$config;

            $gateConfig = new department_gate_config($config);

            $gate = (new department_gates_o())->add(
                $department,
                (bool)self::getParameter('is_entrance'),
                (bool)self::getParameter('is_exit'),
                (string)self::getParameter('name'),
                $gateConfig,
            );

            (new logs_o())->add('department_gates', 'global', 1, $user->id, 'ADD_DEPARTMENT_GATE', 'User added department gate');
            $response->success($gate->asArray(), 201);
        }, [
            'add_department_gate' => 'Add department gate in departments the user has access to',
        ]);

        $this->put('/department/gates', function () {
            global /** @var response $response */ $response;
            $this->requirePermission('update_department_gate');
            $user = (new authentication())->get_user();

            if (!$user) {
                $response->error('Invalid session', 400);
            }

            self::requireParameters(['id']);
            self::requireType(self::getParameter('id'), self::type_int());
            self::requireMinValue((int)self::getParameter('id'), 1);

            $gate = (new department_gates_o())->select((int)self::getParameter('id'));
            if (!$gate->exists()) {
                $response->error('Department gate not found', 404);
            }
            self::requireDepartmentAccess((int)$gate->department->value());

            $data = [];
            if (self::isParametersSet(['is_entrance'])) {
                self::requireType(self::getParameter('is_entrance'), self::type_bool());
                $data['is_entrance'] = (bool)self::getParameter('is_entrance');
            }
            if (self::isParametersSet(['is_exit'])) {
                self::requireType(self::getParameter('is_exit'), self::type_bool());
                $data['is_exit'] = (bool)self::getParameter('is_exit');
            }
            if (self::isParametersSet(['name'])) {
                self::requireType(self::getParameter('name'), self::type_string());
                $data['name'] = (string)self::getParameter('name');
            }
            if (self::isParametersSet(['config'])) {
                self::requireTypeIn(self::getParameter('config'), ['array', 'object']);
                $config = self::getParameter('config');
                $configArray = is_array($config) ? $config : (array)$config;
                $gateConfig = new department_gate_config($configArray);
                $gateConfig->validate();
                $data['config'] = $gateConfig->toArray();
            }

            $nextIsEntrance = $data['is_entrance'] ?? (bool)$gate->is_entrance->value();
            $nextIsExit = $data['is_exit'] ?? (bool)$gate->is_exit->value();
            if (!$nextIsEntrance && !$nextIsExit) {
                $response->error('Gate must be either entrance, exit or both', 400);
            }

            if (empty($data)) {
                $response->error('No data to update', 400);
            }

            $gate->update($data);
            (new logs_o())->add('department_gates', 'global', 1, $user->id, 'UPDATE_DEPARTMENT_GATE', 'User updated department gate');
            $response->success($gate->asArray());
        }, [
            'update_department_gate' => 'Update department gate in departments the user has access to',
        ]);

        $this->delete('/department/gates', function () {
            global /** @var response $response */ $response;
            $this->requirePermission('delete_department_gate');
            $user = (new authentication())->get_user();

            if (!$user) {
                $response->error('Invalid session', 400);
            }

            self::requireParameters(['id']);
            self::requireType(self::getParameter('id'), self::type_int());
            self::requireMinValue((int)self::getParameter('id'), 1);

            $gate = (new department_gates_o())->select((int)self::getParameter('id'));
            if (!$gate->exists()) {
                $response->error('Department gate not found', 404);
            }
            self::requireDepartmentAccess((int)$gate->department->value());
            $gate->delete();

            (new logs_o())->add('department_gates', 'global', 1, $user->id, 'DELETE_DEPARTMENT_GATE', 'User deleted department gate');
            $response->success('Department gate deleted');
        }, [
            'delete_department_gate' => 'Delete department gate in departments the user has access to',
        ]);

        $this->get('/department/relays', function () {
            global /** @var response $response */ $response;
            $this->requirePermission('list_department_relays');
            $user = (new authentication())->get_user();

            if (!$user) {
                $response->error('Invalid session', 400);
            }

            $relays_o = new department_relays_o();

            if (self::isParametersSet(['id'])) {
                self::requireType(self::getParameter('id'), self::type_int());
                self::requireMinValue((int)self::getParameter('id'), 1);
                $relay = (new department_relays_o())->select((int)self::getParameter('id'));
                if (!$relay->exists()) {
                    $response->error('Department relay not found', 404);
                }
                self::requireDepartmentAccess((int)$relay->department->value());
                $response->success($relay->asArray());
            }

            $result = $relays_o->listObjectsWithPaginationIfSet(
                function ($tmp_object_array) {
                    return (new department_relays_o())->select((int)$tmp_object_array['id'])->asArray();
                },
                $relays_o->forceRestrictFilters([
                    'department' => $user->getGroup()->getDepartments(),
                ])
            );

            (new logs_o())->add('department_relays', 'global', 1, $user->id, 'LIST_DEPARTMENT_RELAYS', 'User listed department relays');
            $response->success($result);
        }, [
            'list_department_relays' => 'List department relays in departments the user has access to',
        ]);

        $this->post('/department/relays', function () {
            global /** @var response $response */ $response;
            $this->requirePermission('add_department_relay');
            $user = (new authentication())->get_user();

            if (!$user) {
                $response->error('Invalid session', 400);
            }

            self::requireParameters(['department', 'relay_id', 'name', 'type', 'config']);
            self::requireType(self::getParameter('department'), self::type_int());
            self::requireMinValue((int)self::getParameter('department'), 1);
            self::requireType(self::getParameter('relay_id'), self::type_string());
            self::requireType(self::getParameter('name'), self::type_string());
            self::requireType(self::getParameter('type'), self::type_string());
            self::requireTypeIn(self::getParameter('config'), ['array', 'object']);
            self::requireDepartmentAccess((int)self::getParameter('department'));

            $department = (new departments_o())->select((int)self::getParameter('department'));
            if (!$department->exists()) {
                $response->error('Department not found', 404);
            }

            $config = self::getParameter('config');
            $config = is_array($config) ? $config : (array)$config;

            $relayConfig = new department_relay_config($config);

            $relay = (new department_relays_o())->add(
                $department,
                (string)self::getParameter('relay_id'),
                (string)self::getParameter('name'),
                (string)self::getParameter('type'),
                $relayConfig,
            );

            (new logs_o())->add('department_relays', 'global', 1, $user->id, 'ADD_DEPARTMENT_RELAY', 'User added department relay');
            $response->success($relay->asArray(), 201);
        }, [
            'add_department_relay' => 'Add department relay in departments the user has access to',
        ]);

        $this->put('/department/relays', function () {
            global /** @var response $response */ $response;
            $this->requirePermission('update_department_relay');
            $user = (new authentication())->get_user();

            if (!$user) {
                $response->error('Invalid session', 400);
            }

            self::requireParameters(['id']);
            self::requireType(self::getParameter('id'), self::type_int());
            self::requireMinValue((int)self::getParameter('id'), 1);

            $relay = (new department_relays_o())->select((int)self::getParameter('id'));
            if (!$relay->exists()) {
                $response->error('Department relay not found', 404);
            }
            self::requireDepartmentAccess((int)$relay->department->value());

            $data = [];
            if (self::isParametersSet(['relay_id'])) {
                self::requireType(self::getParameter('relay_id'), self::type_string());
                $data['relay_id'] = (string)self::getParameter('relay_id');
            }
            if (self::isParametersSet(['name'])) {
                self::requireType(self::getParameter('name'), self::type_string());
                $data['name'] = (string)self::getParameter('name');
            }
            if (self::isParametersSet(['type'])) {
                self::requireType(self::getParameter('type'), self::type_string());
                $data['type'] = (string)self::getParameter('type');
            }
            if (self::isParametersSet(['config'])) {
                self::requireTypeIn(self::getParameter('config'), ['array', 'object']);
                $config = self::getParameter('config');
                $configArray = is_array($config) ? $config : (array)$config;
                $relayConfig = new department_relay_config($configArray);
                $relayConfig->validate($data['type'] ?? (string)$relay->type->value());
                $data['config'] = $relayConfig->toArray();
            }

            if (empty($data)) {
                $response->error('No data to update', 400);
            }

            $relay->update($data);
            (new logs_o())->add('department_relays', 'global', 1, $user->id, 'UPDATE_DEPARTMENT_RELAY', 'User updated department relay');
            $response->success($relay->asArray());
        }, [
            'update_department_relay' => 'Update department relay in departments the user has access to',
        ]);

        $this->delete('/department/relays', function () {
            global /** @var response $response */ $response;
            $this->requirePermission('delete_department_relay');
            $user = (new authentication())->get_user();

            if (!$user) {
                $response->error('Invalid session', 400);
            }

            self::requireParameters(['id']);
            self::requireType(self::getParameter('id'), self::type_int());
            self::requireMinValue((int)self::getParameter('id'), 1);

            $relay = (new department_relays_o())->select((int)self::getParameter('id'));
            if (!$relay->exists()) {
                $response->error('Department relay not found', 404);
            }
            self::requireDepartmentAccess((int)$relay->department->value());
            $relay->delete();

            (new logs_o())->add('department_relays', 'global', 1, $user->id, 'DELETE_DEPARTMENT_RELAY', 'User deleted department relay');
            $response->success('Department relay deleted');
        }, [
            'delete_department_relay' => 'Delete department relay in departments the user has access to',
        ]);
    }
}
