<?php

namespace routes;

use classes\authentication;
use objects\categories_o;
use objects\department_categories_o;
use objects\department_variables_o;
use objects\departments_o;
use objects\logs_o;
use objects\orders_o;
use traits\route_t;

class departmentsRoute
{
    use route_t;

    public function run(): void
    {
        $this->get('/departments', function () {
            // Require the user to be logged in
            global $response;
            $this->requirePermission('list_departments');
            // Get the user object
            $user = (new authentication())->get_user();
            // Check if the request was successful
            if ($user) {
                // Log the incident
                (new logs_o())->add('departments', 'global', 1, $user->id, 'LIST_DEPARTMENTS', 'Successfully listed departments');
                // Check if the id is set in the request
                if (self::isParametersSet(['id'])) {
                    // Return the department
                    $response->success(
                        (new departments_o())->select((int)self::getParameter('id'))->asArray([
                            'slack_webhook' => $user->hasPermission('view_slack_webhook')
                        ])
                    );
                }
                $departments_o = new departments_o();
                // Return the list of departments
                $response->success(
                    $departments_o
                        ->setSearchableFields([
                            // The fields that can be searched. This would otherwise make it possible to get secret information from the database, simply by searching for it and getting the result count back
                            'id',
                            'name',
                            'description',
                            'economic_department_id',
                            'visible',
                            'longitude',
                            'latitude',
                        ])
                        ->listObjectsWithPaginationIfSet(
                            function ($department) use ($user) {
                                $tmp_department = [
                                    'id' => (int)$department['id'],
                                    'name' => (string)$department['name'],
                                    'description' => $department['description'],
                                    'economic_department_id' => (int)$department['economic_department_id'],
                                    'created_at' => (string)$department['created_at'],
                                    'updated_at' => (string)$department['updated_at'],
                                    'dimension' => (int)$department['dimension'],
                                    'branding' => (int)$department['branding'],
                                    'longitude' => (float)$department['longitude'],
                                    'latitude' => (float)$department['latitude'],
                                    'order_priority' => (int)$department['order_priority'],
                                ];
                                // If the user has the permission to view the slack webhook, add it to the response
                                if ($user->hasPermission('view_slack_webhook')) {
                                    $tmp_department['slack_webhook'] = $department['slack_webhook'];
                                }
                                return $tmp_department;
                            },
                            $departments_o->forceRestrictFilters([
                                'visible' => 1, // Only show visible departments, this is to prevent showing internal system departments to the end-user.
                            ])
                        )
                );
            } else {
                // Log the incident
                (new logs_o())->add('departments', 'global', 1, 0, 'LIST_DEPARTMENTS', 'No user found, or invalid session');
                // Return an error
                $response->error('Invalid session', 400);
            }
        },
            [
                'list_departments' => 'List all departments',
                'view_slack_webhook' => 'View the slack webhook'
            ]
        );

        $this->post('/departments', function () {
            // Require the user to be logged in
            global $response;
            $this->requirePermission('add_department');
            // Get the user object
            $user = (new authentication())->get_user();
            // Check if the request was successful
            if ($user) {
                // Get the post data
                $data = json_decode(file_get_contents('php://input'), true);
                // Check if the required fields are set
                if (!isset($data['name'])) {
                    $response->error('Name is required', 400);
                }
                if (!isset($data['description'])) {
                    $response->error('Description is required', 400);
                }

                // Add the department
                (new departments_o())->create($data['name'], $data['description']);
                // Log the incident
                (new logs_o())->add('departments', 'global', 1, $user->id, 'ADD_DEPARTMENT', 'Successfully added a department ' . $data['name']);
                // Return a success message
                $response->success(['message' => 'Department added successfully']);
            } else {
                // Log the incident
                (new logs_o())->add('departments', 'global', 1, 0, 'ADD_DEPARTMENT', 'No user found, or invalid session');
                // Return an error
                $response->error('Invalid session', 400);
            }
        },
            [
                'add_department' => 'Add a department'
            ]
        );

        $this->put('/departments', function () {
            // Require the user to be logged in
            global $response;
            self::requirePermission('edit_department');
            // Get the user object
            $user = (new authentication())->get_user();
            // Check if the request was successful
            if ($user) {
                // Require the required fields
                self::requireParameters(['id']);
                // Validate the required fields
                self::requireType((int)self::getParameter('id'), self::TYPE_INT());
                // Get the department object
                $department = (new departments_o())->select(self::getParameter('id'));
                // Update the fields provided
                if (self::isParametersSet(['name'])) {
                    $department->name->set(self::getParameter('name'));
                }
                if (self::isParametersSet(['description'])) {
                    $department->description->set(self::getParameter('description'));
                }
                if (self::isParametersSet(['economic_department_id'])) {
                    $department->economic_department_id->set(self::getParameter('economic_department_id'));
                }
                if (self::isParametersSet(['latitude'])) {
                    $department->latitude->set(self::getParameter('latitude'));
                }
                if (self::isParametersSet(['longitude'])) {
                    $department->longitude->set(self::getParameter('longitude'));
                }
                if (self::isParametersSet(['order_priority'])) {
                    $department->order_priority->set((int)self::getParameter('order_priority'));
                }
                // Log the incident
                (new logs_o())->add('departments', (int)self::getParameter('id'), 1, $user->id, 'EDIT_DEPARTMENT', 'Successfully edited a department');
                // Return a success message
                $response->success(['message' => 'Department updated successfully']);
            } else {
                // Log the incident
                (new logs_o())->add('departments', 'global', 1, 0, 'EDIT_DEPARTMENT', 'No user found, or invalid session');
                // Return an error
                $response->error('Invalid session', 400);
            }
        },
            [
                'edit_department' => 'Edit a department'
            ]
        );

        $this->get('/departments/categories', function () {
            // Require the user to be logged in
            global $response;
            self::requirePermission('list_department_categories');
            // Get the user object
            $user = (new authentication())->get_user();
            // Check if the request was successful
            if ($user) {
                // Require the department id
                self::requireParameters(['id']);
                self::requireType((int)self::getParameter('id'), self::TYPE_INT());
                // Get the department object
                $department = (new departments_o())->select(self::getParameter('id'));
                // Validate the department categories object
                if (!$department->exists()) {
                    // Log the incident
                    (new logs_o())->add('departments', 'global', 1, $user->id, 'LIST_DEPARTMENT_CATEGORIES', 'Department categories not found');
                    // Return an error
                    $response->error('Department categories not found', 400);
                }
                // Get the department categories
                $department_categories = new department_categories_o();
                // Log the incident
                (new logs_o())->add('departments', 'global', 1, $user->id, 'LIST_DEPARTMENT_CATEGORIES', 'Successfully listed department categories');
                // Return the list of department categories
                $response->success(
                    $department_categories
                        ->getCategoriesForDepartment(self::getParameter('id'),
                            function ($department_category) {
                                return [
                                    'id' => (int)$department_category['id'],
                                    'department_id' => (int)$department_category['department_id'],
                                    'category_id' => (int)$department_category['category_id'],
                                    'created_at' => (string)$department_category['created_at'],
                                    'updated_at' => $department_category['updated_at'],
                                    'category' => $department_category['category']->asArray()
                                ];
                            }
                        )
                );
            } else {
                // Log the incident
                (new logs_o())->add('departments', 'global', 1, 0, 'LIST_DEPARTMENT_CATEGORIES', 'No user found, or invalid session');
                // Return an error
                $response->error('Invalid session', 400);
            }
        },
            [
                'list_department_categories' => 'List all department categories'
            ]
        );

        $this->get('/departments/self-serve/enabled', function () {
            // Require the user to be logged in
            global $response;
            self::requirePermission('view_department_selfserve_enabled');
            // Get the user object
            $user = (new authentication())->get_user();
            // Check if the request was successful
            if ($user) {
                // Require the department id
                self::requireParameters(['id']);
                self::requireType((int)self::getParameter('id'), self::type_int());
                // Get the department object
                $department = (new departments_o())->select(self::getParameter('id'));
                // Validate the department object
                if (!$department->exists()) {
                    // Return an error
                    $response->error('Department not found', 404);
                }
                // Get the department variable
                $department_variables = (new department_variables_o())->selectDepartment($department->id);
                $enabled = $department_variables->getVariable('selfserve_enabled');

                // Return the status
                $response->success([
                    'enabled' => $enabled === true
                ]);
            } else {
                // Return an error
                $response->error('Invalid session', 400);
            }
        },
            [
                'view_department_selfserve_enabled' => 'View if department self-serve is enabled'
            ]
        );

        $this->put('/departments/self-serve/enabled', function () {
            // Require the user to be logged in
            global $response;
            self::requirePermission('edit_department_selfserve_enabled');
            // Get the user object
            $user = (new authentication())->get_user();
            // Check if the request was successful
            if ($user) {
                // Require the department id and enabled status
                self::requireParameters(['id', 'enabled']);
                self::requireType((int)self::getParameter('id'), self::type_int());
                self::requireType((bool)self::getParameter('enabled'), self::type_bool());
                // Get the department object
                $department = (new departments_o())->select(self::getParameter('id'));
                // Validate the department object
                if (!$department->exists()) {
                    // Return an error
                    $response->error('Department not found', 404);
                }
                // Check if the user has access to the department
                self::requireDepartmentAccess($department);
                // Set the department variable
                $department_variables = (new department_variables_o())->selectDepartment($department->id);
                $enabled = self::getParameter('enabled') === 'true' || self::getParameter('enabled') === true || self::getParameter('enabled') === 1 || self::getParameter('enabled') === '1';
                $department_variables->set('selfserve_enabled', $enabled ? 'true' : 'false');

                // Log the incident
                (new logs_o())->add('departments', $department->id, 1, $user->id, 'EDIT_DEPARTMENT_SELFSERVE_ENABLED', 'Successfully edited department self-serve enabled status to ' . ($enabled ? 'true' : 'false'));

                // Return a success message
                $response->success(['message' => 'Department self-serve enabled status updated successfully']);
            } else {
                // Return an error
                $response->error('Invalid session', 400);
            }
        },
            [
                'edit_department_selfserve_enabled' => 'Edit if department self-serve is enabled (Requires department access)',
                'department_access_:id' => 'Access the department'
            ]
        );

        $this->post('/departments/categories', function () {
            // Require the user to be logged in
            global $response;
            self::requirePermission('add_department_category');
            // Get the user object
            $user = (new authentication())->get_user();
            // Check if the request was successful
            if ($user) {
                // Require the parameters
                self::requireParameters(['department_id', 'category_id']);
                self::requireType((int)self::getParameter('department_id'), self::TYPE_INT());
                self::requireType((int)self::getParameter('category_id'), self::TYPE_INT());
                // Get the department object
                $department = (new departments_o())->select(self::getParameter('department_id'));
                // Validate the department object
                if (!$department->exists()) {
                    // Log the incident
                    (new logs_o())->add('departments', 'global', 1, $user->id, 'ADD_DEPARTMENT_CATEGORY', 'Department not found');
                    // Return an error
                    $response->error('Department not found', 400);
                }
                // Get the category object
                $category = (new categories_o())->select(self::getParameter('category_id'));
                // Validate the category object
                if (!$category->exists()) {
                    // Log the incident
                    (new logs_o())->add('departments', 'global', 1, $user->id, 'ADD_DEPARTMENT_CATEGORY', 'Category not found');
                    // Return an error
                    $response->error('Category not found', 400);
                }
                // Add the department category
                $department_categories = new department_categories_o();
                $department_categories->add(
                    self::getParameter('department_id'),
                    self::getParameter('category_id')
                );
                // Log the incident
                (new logs_o())->add('departments', 'global', 1, $user->id, 'ADD_DEPARTMENT_CATEGORY', 'Successfully added a department category');
                // Return a success message
                $response->success(['message' => 'Department category added successfully']);
            } else {
                // Log the incident
                (new logs_o())->add('departments', 'global', 1, 0, 'ADD_DEPARTMENT_CATEGORY', 'No user found, or invalid session');
                // Return an error
                $response->error('Invalid session', 400);
            }
        },
            [
                'add_department_category' => 'Add a department category'
            ]
        );

        $this->delete('/departments/categories', function () {
            // Require the user to be logged in
            global $response;
            self::requirePermission('delete_department_category');
            // Get the user object
            $user = (new authentication())->get_user();
            // Check if the request was successful
            if ($user) {
                // Require the parameters
                self::requireParameters(['id']);
                self::requireType((int)self::getParameter('id'), self::TYPE_INT());
                // Get the department category object
                $department_category = (new department_categories_o())->select(self::getParameter('id'));
                // Validate the department category object
                if (!$department_category->exists()) {
                    // Log the incident
                    (new logs_o())->add('departments', 'global', 1, $user->id, 'DELETE_DEPARTMENT_CATEGORY', 'Department category not found');
                    // Return an error
                    $response->error('Department category not found', 400);
                }
                // Delete the department category
                $department_category->delete();
                // Log the incident
                (new logs_o())->add('departments', 'global', 1, $user->id, 'DELETE_DEPARTMENT_CATEGORY', 'Successfully deleted a department category');
                // Return a success message
                $response->success(['message' => 'Department category deleted successfully']);
            } else {
                // Log the incident
                (new logs_o())->add('departments', 'global', 1, 0, 'DELETE_DEPARTMENT_CATEGORY', 'No user found, or invalid session');
                // Return an error
                $response->error('Invalid session', 400);
            }
        },
            [
                'delete_department_category' => 'Delete a department category'
            ]
        );

        self::get('/departments/order/recommended', function () {
            // Require the user to be logged in
            global $response;
            self::requirePermission('list_department_order_recommended');
            // Get the user object
            $user = (new authentication())->get_user();
            // Check if the request was successful
            if ($user) {
                // Check if the required fields are set
                self::requireParameters(['id']);
                self::requireType((int)self::getParameter('id'), self::TYPE_INT());
                // Get the order
                $order = (new orders_o())->select((int)self::getParameter('id'));
                $order->requireSelected();
                // Check if the user is allowed to view the recommended order for the department
                self::requireDepartmentAccess($order->department_id->value());
                // Get the recommended order
                $recommended_order = $order->getRecommendedOrder();
                // Log the incident
                (new logs_o())->add('departments', 'global', 1, $user->id, 'LIST_DEPARTMENT_ORDER_RECOMMENDED', 'Successfully listed the recommended department order');
                // Return the recommended order
                $response->success($recommended_order);
            } else {
                // Log the incident
                (new logs_o())->add('departments', 'global', 1, 0, 'LIST_DEPARTMENT_ORDER_RECOMMENDED', 'No user found, or invalid session');
                // Return an error
                $response->error('Invalid session', 400);
            }
        },
            [
                'list_department_order_recommended' => 'List the recommended department order',
                'order_access_:id' => 'Access the order',
                'department_access_:id' => 'Access the department'
            ]
        );
    }
}