<?php

namespace routes;

use classes\authentication;
use classes\economic;
use classes\email;
use classes\recaptcha;
use classes\virkdata;
use Exception;
use objects\customer_password_reset_keys_o;
use objects\logs_o;
use objects\tokens_o;
use objects\users_o;
use traits\route_t;

class authRoute
{
    use route_t;

    public function run(): void
    {
        $this->post('/auth/login', function () {
            // Get the post data
            global $response;
            $this->requireRecaptcha();
            $data = json_decode(file_get_contents('php://input'), true);
            if (!is_array($data)) {
                $data = [];
            }
            self::requireParameters(['customer_number', 'password']);
            self::requireType((int)$data['customer_number'], $this->type_int());
            self::requireMinValue((int)$data['customer_number'], 1);
            self::requireType((string)$data['password'], $this->type_string());
            self::requireMinLength('password', 1);
            $data['customer_number'] = (int)$data['customer_number'];
            $data['password'] = (string)$data['password'];
            // Check if the customer number, and password are set
            if (!isset($data['customer_number']) || empty($data['customer_number']) || !is_numeric($data['customer_number']) || $data['customer_number'] < 1) {
                $response->error('Customer number is required', 400);
            }
            if (!isset($data['password']) || empty($data['password']) || strlen($data['password']) < 1) {
                $response->error('Password is required', 400);
            }
            // Try to log the user in
            $isCredentialsValid = (new authentication())->authenticate($data['customer_number'], $data['password']);
            // Log the incident
            if ($isCredentialsValid) {
                (new logs_o())->add('auth', 'global', 1, 0, 'AUTH_SUCCESS', 'Customer number: ' . $data['customer_number']);
            } else {
                (new logs_o())->add('auth', 'global', 1, 0, 'AUTH_FAILURE', 'Customer number: ' . $data['customer_number']);
                $response->error('Invalid credentials', 401);
            }
            // If the credentials are valid, create a token
            $token = (new authentication())->create_token($data['customer_number']);
            // Return the token
            $response->success(['token' => $token]);
        });

        $this->get('/auth/logout', function () {
            // Get the token from the headers
            global $response;
            $token = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
            // Remove the Bearer prefix
            $token = str_replace('Bearer ', '', $token);
            // Check if the token is valid
            if (!(new authentication())->validate_token($token)) {
                $response->error('Invalid token', 401);
            }
            // Delete the token
            (new tokens_o())->delete($token);
            // Return a success message
            $response->success(['message' => 'Logged out']);
        });

        $this->get('/auth/session', function () {
            // Get the token from the headers
            global $response;
            $token = $_SERVER['HTTP_AUTHORIZATION'] ?? ''; // Default to empty string if not set
            // Remove the Bearer prefix
            $token = str_replace('Bearer ', '', $token);
            // Check if the token is valid
            if (!(new authentication())->validate_token($token)) {
                $response->error('Invalid token', 401);
            }
            // Get the user object
            $user = (new authentication())->get_user();
            // Check if the user exists
            if (!$user) {
                $response->error('User not found', 400);
            }
            // Return the (session) user object
            $response->success(
                ($user->includeIncludes(['economicCustomer', 'permissions'])->asArray())
            );
        });

        $this->post('/auth/employee/login', function () {
            // Get the post data
            global $response;
            $this->requireRecaptcha();
            $data = json_decode(file_get_contents('php://input'), true);
            if (!is_array($data)) {
                $data = [];
            }
            // Check if the employee number, and password are set
            if (!isset($data['user_id'])) {
                $response->error('Employee number is required', 400);
            }
            if (!isset($data['password'])) {
                $response->error('Password is required', 400);
            }
            // Try to log the user in
            $isCredentialsValid = (new authentication())->authenticateEmployee($data['user_id'], $data['password']);
            // Log the incident
            if ($isCredentialsValid) {
                (new logs_o())->add('auth', 'global', 1, 0, 'AUTH_SUCCESS', 'Employee number: ' . $data['user_id']);
            } else {
                (new logs_o())->add('auth', 'global', 1, 0, 'AUTH_FAILURE', 'Employee number: ' . $data['user_id']);
                $response->error('Invalid credentials', 401);
            }
            // If the credentials are valid, create a token
            $token = (new authentication())->create_employee_token($data['user_id']);
            // Return the token
            $response->success(['token' => $token]);
        });

        $this->get('/auth/reCAPTCHA/public', function () {
            // Check if the user:
            // 1. Is rate limited (future feature)
            // 2. Is required to solve a reCAPTCHA
            global $response;
            $recaptcha = (new recaptcha())->getPublicConfig();
            $response->success([
                'rate_limit' => [
                    'enabled' => false,
                    'limit' => 0,
                    'remaining' => 0,
                    'reset' => 0,
                    'warning' => null
                ],
                'recaptcha' => $recaptcha
            ]);
        });

        $this->post('/auth/register/cvr', function () {
            // Get the post data
            global $response;
            $this->requireRecaptcha();
            /**
             * {
             * "cvr": "44794780",
             * "companyPhone": 21754690,
             * "invoiceEmail": "mikkel@truckwash.dk",
             * "contactEmail": "mikkel@truckwash.dk",
             * "contactPhone": 21754690,
             * "searchResult": {
             * "vat": 41004355,
             * "status": "Normal",
             * "name": "Truckwash ApS",
             * "address": "Letland Alle 2",
             * "zipcode": 2630,
             * "city": "Taastrup",
             * "protected": true,
             * "phone": "21754690",
             * "website": null,
             * "email": "mikkel@truckwash.dk",
             * "fax": null,
             * "startdate": "2019-12-11",
             * "enddate": null,
             * "employees": 14,
             * "industrycode": 953190,
             * "industrydesc": "Reparation og vedligeholdelse af motorkøretøjer i.a.n.",
             * "companytype": "APS",
             * "companydesc": "Anpartsselskab",
             * "owners": [
             * "DELOITTE STATSAUTORISERET REVISIONSPARTNERSELSKAB",
             * "MBL Revision I/S",
             * "WASH GROUP A/S"
             * ]
             * }
             * }
             */
            /**
             * Parameters:
             */
            self::requireParameters(['cvr', 'companyPhone', 'invoiceEmail', 'contactEmail', 'contactPhone']);
            $cvr = self::getParameter('cvr');
            $companyPhone = (int)self::getParameter('companyPhone');
            $invoiceEmail = self::getParameter('invoiceEmail');
            $contactEmail = self::getParameter('contactEmail');
            $contactPhone = (int)self::getParameter('contactPhone');
            $contactName = self::getParameter('contactName');
            /**
             * Validate
             */
            self::requireType($cvr, $this->type_string());
            self::requireMinLength('cvr', 8);
            self::requireMaxLength('cvr', 20);
            self::requireType($companyPhone, $this->type_int());
            self::requireMinValue($companyPhone, 10000000);
            self::requireMaxValue($companyPhone, 9999999999);
            if (self::isParametersSet(['invoiceEmail']) && !is_null($invoiceEmail)) {
                self::requireType($invoiceEmail, $this->type_string());
                self::requireMinLength('invoiceEmail', 5);
                self::requireMaxLength('invoiceEmail', 255);
            }
            if (self::isParametersSet(['contactEmail']) && !is_null($contactEmail)) {
                self::requireType($contactEmail, $this->type_string());
                self::requireMinLength('contactEmail', 5);
                self::requireMaxLength('contactEmail', 255);
            }
            /**
             * If the contact phone is set, validate it
             */
            if (self::isParametersSet(['contactPhone']) && !empty($contactPhone)) {
                self::requireType($contactPhone, $this->type_int());
                self::requireMinValue($contactPhone, 10000000);
                self::requireMaxValue($contactPhone, 9999999999);
            }

            /**
             * If the contact phone is empty, default to company phone
             */
            if (empty($contactPhone)) {
                $contactPhone = $companyPhone;
            }
            /**
             * If the emails are empty, default to jb@truckwash.dk
             */
            if (empty($invoiceEmail)) {
                $invoiceEmail = 'jb@truckwash.dk';
            }
            if (empty($contactEmail)) {
                $contactEmail = 'jb@truckwash.dk';
            }

            /**
             * Check if the cvr already exists
             */
            $economic_response = ((new economic())->customers->customers->search([
                'corporateIdentificationNumber' => (string)$cvr,
            ], [
                'skipPages' => 0,
                'pageSize' => 1, // Since the limit is 1000, we need to set the page size to 1000.
            ])->collection);
            if (count($economic_response) === 0) {
                /**
                 * Create the customer in E-conomic
                 */
                // Get the customer name
                $name = (new virkdata())->getCompanyInformation($cvr, '', [])->name;
                /**
                 * $economic = new economic();
                 * $economic->createCustomer(
                 * $customer_number,
                 * $name,
                 * $cvr,
                 * $invoiceEmail,
                 * $companyPhone,
                 * );
                 */
                $economic = new economic();
                $result = $economic->createCustomer(
                    (int)$companyPhone,
                    $name,
                    (string)$cvr,
                    $invoiceEmail,
                    (string)$companyPhone,
                );
                /**
                 * Return the result
                 */
                $response->success($result, 201);
            } else {
                $response->error('CVR already registered', 400);
            }
        });

        $this->post('/auth/password-reset/request', function () {
            global $response;
            $this->requireRecaptcha();
            self::requireParameters(['customer_number']);
            $customer_number = (int)self::getParameter('customer_number');

            $user = (new users_o())->getUserByCustomerNumber($customer_number);
            if (!$user->id) {
                // For security reasons, don't reveal if the user exists
                $response->success(['message' => 'If the customer exists, a password reset email has been sent.']);
            }

            $email_address = $user->email->value();
            if (empty($email_address)) {
                // If no email is set, we can't send the reset email
                $response->error('No email address associated with this account. Please contact support.', 400);
            }

            // Generate token
            $token = customer_password_reset_keys_o::generateToken();

            // Save token
            $reset_key_o = new customer_password_reset_keys_o();
            $reset_key_o->add([
                'customer_id' => $customer_number,
                'token' => $token,
                'note' => 'Requested via API'
            ]);

            // Send email
            $email = new email();
            $reset_link = "https://truckwash.io/auth/password-reset/" . $token;

            $subject = 'Adgangskode nulstilling';
            $message = "Du har anmodet om at nulstille din adgangskode. Klik på linket herunder for at fortsætte:<br><br><a href='$reset_link'>$reset_link</a><br><br>Linket er gyldigt i 1 time.";

            try {
                $email->sendEmail($email_address, $user->display_name->value() ?? 'Kunde', $subject, $message, null);
                $response->success(['message' => 'If the customer exists, a password reset email has been sent.']);
            } catch (Exception $e) {
                $response->error('Failed to send email: ' . $e->getMessage(), 500);
            }
        });

        $this->get('/auth/password-reset/validate', function () {
            global $response;
            self::requireParameters(['token']);
            $token = self::getParameter('token');

            $reset_key_o = new customer_password_reset_keys_o();
            $found_key = $reset_key_o->findValidByToken($token);

            if ($found_key === null) {
                $response->error('Invalid or expired token', 404);
            }

            $response->success([
                'valid' => true,
                'customer_id' => $found_key->customer_id->value()
            ]);
        });

        $this->post('/auth/password-reset/set', function () {
            global $response;
            $this->requireRecaptcha();
            self::requireParameters(['token', 'password']);
            $token = self::getParameter('token');
            $password = self::getParameter('password');

            $reset_key_o = new customer_password_reset_keys_o();
            $found_key = $reset_key_o->findValidByToken($token);

            if ($found_key === null) {
                $response->error('Invalid or expired token', 404);
            }

            try {
                $found_key->setPassword($password);
                $response->success(['message' => 'Password updated successfully']);
            } catch (Exception $e) {
                $response->error($e->getMessage(), 400);
            }
        });
    }
}