<?php

namespace routes;

use classes\authentication;
use classes\email;
use classes\response;
use classes\router;
use classes\stripe;
use objects\departments_o;
use objects\logs_o;
use objects\orders_o;
use objects\stripe_module_customers_o;
use traits\route_t;

class moduleStripeRoute
{
    use route_t;

    public function run(): void
    {
        global /** @var response $response */
        /** @var router $router */
        $router, $response;


        /** Modules > Stripe > Customers > List */
        $this->get('/modules/stripe/customers', function () {
            global $response;
            self::requirePermission('modules_stripe_customers_list');
            $user = (new authentication())->get_user();
            if ($user) {
                (new logs_o())->add('modules_stripe', 'global', 1, 0, 'MODULES_STRIPE', 'User accessed the customers list');
                $result = (new stripe())->customers->list();
                $response->success((object)$result);
            } else {
                (new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to access the customers list without a valid session');
                $response->error('Invalid session', 400);
            }
        },
            [
                'modules_stripe_customers_list' => 'List all customers'
            ]
        );

        /** Modules > Stripe > Products > List */
        $this->get('/modules/stripe/products', function () {
            global $response;
            self::requirePermission('modules_stripe_products_list');
            $user = (new authentication())->get_user();
            if ($user) {
                (new logs_o())->add('modules_stripe', 'global', 1, 0, 'MODULES_STRIPE', 'User accessed the products list');
                $result = (new stripe())->product->list();
                $response->success((object)$result);
            } else {
                (new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to access the products list without a valid session');
                $response->error('Invalid session', 400);
            }
        },
            [
                'modules_stripe_products_list' => 'List all products'
            ]
        );

        /** Modules > Stripe > Prices > List */
        $this->get('/modules/stripe/prices', function () {
            global $response;
            self::requirePermission('modules_stripe_prices_list');
            $user = (new authentication())->get_user();
            if ($user) {
                (new logs_o())->add('modules_stripe', 'global', 1, 0, 'MODULES_STRIPE', 'User accessed the prices list');
                $result = (new stripe())->prices->list();
                $response->success((object)$result);
            } else {
                (new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to access the prices list without a valid session');
                $response->error('Invalid session', 400);
            }
        },
            [
                'modules_stripe_prices_list' => 'List all prices'
            ]
        );

        /** Modules > Stripe > Send Invoice */
        $this->post('/modules/stripe/invoice', function () {
            global $response;
            self::requirePermission('modules_stripe_invoice_send');
            $user = (new authentication())->get_user();
            if ($user) {
                self::requireParameters(['email', 'order_id']);
                self::requireType(self::fromRequest('email'), 'string');
                self::requireType((int)self::fromRequest('order_id'), self::TYPE_INT());
                self::requireMinLength('email', 4);
                self::requireMaxLength('email', 255);
                self::requireMinLength('order_id', 1);
                self::requireMaxLength('order_id', 255);
                // Check if the email is valid
                if (!filter_var(self::fromRequest('email'), FILTER_VALIDATE_EMAIL)) {
                    $response->error('Invalid email', 400);
                }
                // Check if the order exists
                $order = (new orders_o())->select((int)self::fromRequest('order_id'));
                $order->requireSelected();
                // Log the action
                (new logs_o())->add('modules_stripe', 'global', 1, $user->id, 'MODULES_STRIPE', 'User sent an invoice');
                // Create a customer account, if it doesn't exist
                $hasCustomerAccount = (new stripe_module_customers_o())->doesCustomerHaveAccount((string)self::fromRequest('email'));
                if (!$hasCustomerAccount) {
                    $customer = (new stripe())->customers->create((string)self::fromRequest('email'));
                    (new stripe_module_customers_o())->add((string)self::fromRequest('email'), $customer->id);
                } else {
                    // Get the customer account by email
                    $customer = (new stripe())->customers->retrieve(
                    // Get the customer ID
                        (new stripe_module_customers_o())
                            ->getCustomerId(
                                (string)self::fromRequest('email')
                            )
                    );
                }
                // Create an invoice
                $invoice = (new stripe())->invoice->generate((int)self::fromRequest('order_id'), $customer->id);
                // Set the order stripe invoice details
                $order->setStripeInvoicing($invoice->id, $customer->id, $invoice->hosted_invoice_url);
                $email = new email();
                $email->sendStripeInvoiceEmail(
                    (string)self::fromRequest('email'),
                    null,
                    $invoice->hosted_invoice_url,
                    (int)self::fromRequest('order_id')
                );
                // Return the result
                $response->success((object)$invoice);
            } else {
                (new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to send an invoice without a valid session');
                $response->error('Invalid session', 400);
            }
        },
            [
                'modules_stripe_invoice_send' => 'Send invoice'
            ]
        );

        self::get('/modules/stripe/terminal/readers', function () {
            global $response;
            self::requirePermission('modules_stripe_terminal_readers_list');
            $user = (new authentication())->get_user();
            if ($user) {
                (new logs_o())->add('modules_stripe', 'global', 1, 0, 'MODULES_STRIPE', 'User accessed the readers list');
                $result = (new stripe())->readers->list();
                $response->success((object)$result);
            } else {
                (new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to access the readers list without a valid session');
                $response->error('Invalid session', 400);
            }
        },
            [
                'modules_stripe_terminal_readers_list' => 'List all Stripe terminal readers'
            ]
        );

        self::get('/modules/stripe/terminal/locations', function () {
            global $response;
            self::requirePermission('modules_stripe_terminal_locations_list');
            $user = (new authentication())->get_user();
            if ($user) {
                (new logs_o())->add('modules_stripe', 'global', 1, 0, 'MODULES_STRIPE', 'User accessed the terminal locations list');
                $result = (new stripe())->readers->listLocations();
                $response->success((object)$result);
            } else {
                (new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to access the terminal locations list without a valid session');
                $response->error('Invalid session', 400);
            }
        },
            [
                'modules_stripe_terminal_locations_list' => 'List all Stripe terminal locations'
            ]
        );

        self::get('/modules/stripe/department/terminal/location',
            function () {
                global $response;
                self::requirePermission('modules_stripe_department_terminal_location_list');
                self::requireParameters(['id']);
                self::requireType((int)self::fromRequest('id'), self::TYPE_INT());
                // Require the id to be above 0
                if ((int)self::fromRequest('id') < 1) {
                    $response->error('Invalid department ID', 400);
                }
                $user = (new authentication())->get_user();
                if ($user) {
                    // Make sure the user has access to the department
                    self::requireDepartmentAccess((int)self::fromRequest('id'));
                    // Make sure the department exists
                    $department = (new departments_o())->select((int)self::fromRequest('id'));
                    $department->requireSelected();
                    (new logs_o())->add('modules_stripe', 'global', 1, 0, 'MODULES_STRIPE', 'User accessed the department terminal location');
                    // Get the department terminal location
                    $isSet = $department->isStripeTerminalLocationSet();
                    // Return the result if the department terminal location is set, otherwise return null
                    $response->success([
                        'id' => (
                        $isSet
                            ? $department->getStripeTerminalLocation()
                            : null
                        )
                    ]);
                } else {
                    (new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to access the department terminal location without a valid session');
                    $response->error('Invalid session', 400);
                }
            },
            [
                'modules_stripe_department_terminal_location_list' => 'List all department terminal location',
                'department_access_:id' => 'Access department. - :id'
            ]
        );

        self::post('/modules/stripe/department/terminal/location',
            function () {
                global $response;
                self::requirePermission('modules_stripe_department_terminal_location_set');
                self::requireParameters(['id', 'location']);
                self::requireType((int)self::fromRequest('id'), self::TYPE_INT());
                self::requireType((string)self::fromRequest('location'), 'string');
                self::requireMinLength('location', 1);
                self::requireMaxLength('location', 255);
                // Require the id to be above 0
                if ((int)self::fromRequest('id') < 1) {
                    $response->error('Invalid department ID', 400);
                }
                $user = (new authentication())->get_user();
                if ($user) {
                    // Make sure the user has access to the department
                    self::requireDepartmentAccess((int)self::fromRequest('id'));
                    // Make sure the department exists
                    $department = (new departments_o())->select((int)self::fromRequest('id'));
                    $department->requireSelected();
                    (new logs_o())->add('modules_stripe', 'global', 1, 0, 'MODULES_STRIPE', 'User set the department terminal location');
                    // Set the department terminal location
                    $department->setStripeTerminalLocation((string)self::fromRequest('location'));
                    // Return the result
                    $response->success([
                        'id' => $department->getStripeTerminalLocation()
                    ]);
                } else {
                    (new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to set the department terminal location without a valid session');
                    $response->error('Invalid session', 400);
                }
            },
            [
                'modules_stripe_department_terminal_location_set' => 'Set department terminal location',
                'department_access_:id' => 'Access department. - :id'
            ]
        );

        self::get('/modules/stripe/department/terminal/readers',
            function () {
                global $response;
                self::requirePermission('modules_stripe_department_terminal_readers_list');
                self::requireParameters(['id']);
                self::requireType((int)self::fromRequest('id'), self::TYPE_INT());
                // Require the id to be above 0
                if ((int)self::fromRequest('id') < 1) {
                    $response->error('Invalid department ID', 400);
                }
                $user = (new authentication())->get_user();
                if ($user) {
                    // Make sure the user has access to the department
                    self::requireDepartmentAccess((int)self::fromRequest('id'));
                    // Make sure the department exists
                    $department = (new departments_o())->select((int)self::fromRequest('id'));
                    $department->requireSelected();
                    (new logs_o())->add('modules_stripe', 'global', 1, 0, 'MODULES_STRIPE', 'User accessed the department terminal readers');
                    // Get the department terminal readers
                    $readers = $department->getStripeTerminalReaders();
                    // Return the result
                    $response->success($readers);
                } else {
                    (new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to access the department terminal readers without a valid session');
                    $response->error('Invalid session', 400);
                }
            },
            [
                'modules_stripe_department_terminal_readers_list' => 'List all department terminal readers',
                'department_access_:id' => 'Access department. - :id'
            ]
        );
    }
}