<?php

namespace routes;

use classes\authentication;
use objects\branding_o;
use objects\logs_o;
use traits\route_t;

class BrandingRoute
{
    use route_t;

    private const BRANDING_FIELDS = [
        'name' => 'string',
        'description' => 'string',
        'cvr' => 'int',
        'address' => 'string',
        'phone_country_code' => 'int',
        'phone' => 'int',
        'email' => 'string',
        'website' => 'string',
        'banner' => 'string',
        'logo' => 'string',
        'favicon' => 'string',
        'signature' => 'string',
    ];

    private function readBrandingPayload(array $requiredFields = []): array
    {
        global $response;

        $payload = [];
        foreach (self::BRANDING_FIELDS as $field => $type) {
            if (!self::isParametersSet([$field])) {
                continue;
            }

            $value = self::getParameter($field);
            if ($value === '') {
                $value = null;
            }

            if ($value === null) {
                if (in_array($field, $requiredFields, true)) {
                    $response->error($field . ' is required', 400);
                }
                $payload[$field] = null;
                continue;
            }

            if ($type === 'int') {
                if (is_int($value)) {
                    $payload[$field] = $value;
                    continue;
                }

                if (is_string($value) && preg_match('/^-?\d+$/', $value) === 1) {
                    $payload[$field] = (int)$value;
                    continue;
                }

                $response->error($field . ' must be an integer', 400);
            }

            if (!is_string($value)) {
                $response->error($field . ' must be a string', 400);
            }

            $payload[$field] = $value;
        }

        foreach ($requiredFields as $requiredField) {
            if (!array_key_exists($requiredField, $payload)) {
                $response->error($requiredField . ' is required', 400);
            }
        }

        return $payload;
    }

    private function applyBrandingPayload(branding_o $branding, array $payload): void
    {
        foreach ($payload as $field => $value) {
            if (!array_key_exists($field, self::BRANDING_FIELDS) || !property_exists($branding, $field)) {
                continue;
            }

            $branding->{$field}->set($value);
        }

        $branding->objectChanged();
    }

    public function run(): void
    {
        $this->get('/branding', function () {

            // Require the user to be logged in
            global $response;
            $this->requirePermission('list_branding_options');
            // Get the user object
            $user = (new authentication())->get_user();
            // Check if the request was successful
            if ($user) {
                // Log the incident
                (new logs_o())->add('branding', 'global', 1, $user->id, 'LIST_BRANDING_OPTIONS', 'User listed branding options');
                // Check the user has specified the branding id
                if (self::isParametersSet(['id'])) {
                    // Check if the parameters are of the correct type
                    self::requireType((int)self::getParameter('id'), self::TYPE_INT());
                    self::requireMinValue((int)self::getParameter('id'), 1);
                    // Select the object
                    $branding = (new branding_o())->select(self::getParameter('id'));
                    // Check if the object exists
                    if ($branding->exists()) {
                        // Return the object as an array
                        $response->success(
                            $branding->asArray()
                        );
                    } else {
                        // Log the incident
                        (new logs_o())->add('branding', 'global', 1, $user->id, 'LIST_BRANDING_OPTIONS', 'User tried to list branding options with an invalid id');
                        // Return an error
                        $response->error('Invalid id', 400);
                    }
                }
                // Return the list of departments
                $response->success(
                    (new branding_o())
                        ->listObjectsWithPaginationIfSet(
                            function ($branding) use ($user) {
                                // Return the object as an array
                                $tmp_branding = (new branding_o())->select($branding['id']);
                                return $tmp_branding->asArray();
                            }
                        )
                );
            } else {
                // Log the incident
                (new logs_o())->add('branding', 'global', 1, 0, 'LIST_BRANDING_OPTIONS', 'User tried to list branding options without being logged in');
                // Return an error
                $response->error('Invalid session', 400);
            }
        },
            [
                'list_branding_options' => 'List all product options'
            ]
        );

        $this->post('/branding', function () {
            // Require the user to be logged in
            global $response;
            $this->requirePermission('add_branding_option');
            // Get the user object
            $user = (new authentication())->get_user();
            // Check if the request was successful
            if ($user) {
                // Check if the required parameters are set
                self::requireParameters(['name', 'description', 'cvr']);
                // Create the object
                $branding = new branding_o();
                // Add the object
                $branding->add($this->readBrandingPayload(['name', 'description', 'cvr']));
                // Log the incident
                (new logs_o())->add('branding', 'global', 1, $user->id, 'ADD_BRANDING_OPTION', 'User added a branding option');
                // Return the object
                $response->success(
                    $branding->asArray()
                );
            } else {
                // Log the incident
                (new logs_o())->add('branding', 'global', 1, 0, 'ADD_BRANDING_OPTION', 'User tried to add a branding option without being logged in');
                // Return an error
                $response->error('Invalid session', 400);
            }
        },
            [
                'add_branding_option' => 'Add a branding option'
            ]
        );

        $this->put('/branding', function () {
            // Require the user to be logged in
            global $response;
            $this->requirePermission('edit_branding_option');
            // Get the user object
            $user = (new authentication())->get_user();
            // Check if the request was successful
            if ($user) {
                // Check if the required parameters are set
                self::requireParameters(['id']);
                // Check if the parameters are of the correct type
                self::requireType(self::getParameter('id'), self::TYPE_INT());
                // Create the object
                $branding = new branding_o();
                // Select the object
                $branding->select(self::getParameter('id'));
                if (!$branding->exists()) {
                    $response->error('Invalid id', 400);
                }

                $payload = $this->readBrandingPayload();
                $this->applyBrandingPayload($branding, $payload);

                // Log the incident
                (new logs_o())->add('branding', 'global', 1, $user->id, 'EDIT_BRANDING_OPTION', 'User edited a branding option');
                // Return the object
                $response->success(
                    $branding->asArray()
                );
            } else {
                // Log the incident
                (new logs_o())->add('branding', 'global', 1, 0, 'EDIT_BRANDING_OPTION', 'User tried to edit a branding option without being logged in');
                // Return an error
                $response->error('Invalid session', 400);
            }
        },
            [
                'edit_branding_option' => 'Edit a branding option'
            ]
        );
    }
}
