<?php

namespace routes;

use classes\authentication;
use classes\customer_mass_import_service;
use customers\economicCustomers;
use objects\logs_o;
use objects\users_o;
use traits\route_t;

class customerSearchRoute
{
    use route_t;

    public function run(): void
    {
        //TODO: Remove this, this is deprecated in favor of the new search endpoint
        $this->post('/customers/search', function () {
            // Require the user to be logged in
            global $response;
            $this->requirePermission('search_customers');
            // 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 pagination, search and sort parameters are set
                if (!isset($data['search'])) {
                    $response->error('Missing required body parameter search', 400);
                }
                if (!isset($data['filter'])) {
                    $response->error('Missing required body parameter filter', 400);
                }
                // Check if the search parameter is valid
                $allowedSearchFilters = (new economicCustomers())->allowed_search_filters_customers();
                if (!in_array($data['filter'], $allowedSearchFilters)) {
                    $response->error('Invalid search parameter', 400);
                }
                (new logs_o())->add('customers', 'global', 1, $user->id, 'SEARCH_CUSTOMERS', 'Successfully retrieved customers meeting search criteria');
                // Return the list of users
                $response->success(
                    (array)(new economicCustomers())->searchCustomers((string)$data['search'], (string)$data['filter'])
                );
            } else {
                // Log the incident
                (new logs_o())->add('customers', 'global', 1, 0, 'SEARCH_CUSTOMERS', 'No user found, or invalid session');
                // Return an error
                $response->error('Invalid session', 400);
            }
        },
            [
                'search_customers' => 'Search for customers'
            ]
        );

        self::get('/customers', function () {
            // Require the user to be logged in
            global $response;
            self::requirePermission('search_customers');
            // Get the user object
            $user = (new authentication())->get_user();
            // Check if the request was successful
            if ($user) {
                // Check if the pagination parameters are set
                $page = self::fromRequest('page') ?? 1;
                $limit = self::fromRequest('limit') ?? 100;
                $search = self::fromRequest('search') ?? null;
                $barred = self::fromRequest('barred') ?? null;
                // Create the economic customers object
                $economicCustomers = new economicCustomers();
                try {
                    $result = (object)$economicCustomers->listCustomers(
                        (int)$page,
                        (int)$limit,
                        $search,
                        $barred
                    );

                    if (!isset($result->pagination) || !is_object($result->pagination) || !isset($result->pagination->results) || !is_numeric($result->pagination->results)) {
                        throw new \RuntimeException('Malformed e-conomic customers response: missing pagination results.');
                    }
                    if (!isset($result->collection) || !is_array($result->collection)) {
                        throw new \RuntimeException('Malformed e-conomic customers response: missing customer collection.');
                    }
                } catch (\Throwable $throwable) {
                    $upstreamMessage = self::sanitizeUpstreamErrorMessage($throwable);
                    $searchProvided = (is_string($search) && trim($search) !== '') ? 'true' : 'false';
                    $context = json_encode([
                        'page' => (int)$page,
                        'limit' => (int)$limit,
                        'search_provided' => $searchProvided,
                        'barred' => $barred,
                    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

                    (new logs_o())->add(
                        'customers',
                        'global',
                        1,
                        $user->id,
                        'LIST_CUSTOMERS_FAILED',
                        'Failed to list customers from e-conomic: ' . $upstreamMessage . ' | context=' . $context
                    );

                    $response->error([
                        'message' => 'Failed to fetch customers from e-conomic',
                        'upstream_message' => $upstreamMessage,
                    ], 502);
                }

                // Parse the pagination meta from E-conomic to the standard format used in this application
                $response->paginate(
                    (int)$page,
                    (int)$limit,
                    (int)$result->pagination->results,
                    $search,
                    ['barred' => $barred]
                );
                // Create the users object
                $users_o = new users_o();
                $customers = self::parseFunction($result->collection, function ($customer) use ($users_o) {
                    // Add the user id to the customer object
                    $customer->id = null;
                    // Update the user id if the customer is imported from E-conomic
                    if ($users_o->isImportedFromEconomic($customer->customerNumber)) {
                        $customer->id = $users_o->getUserIdFromEconomic($customer->customerNumber);
                    }
                    return $customer;
                });

                // Log the incident
                (new logs_o())->add('customers', 'global', 1, $user->id, 'LIST_CUSTOMERS', 'Successfully listed customers');
                // Return the list of users
                $response->success($customers);
            } else {
                // Log the incident
                (new logs_o())->add('customers', 'global', 1, 0, 'LIST_CUSTOMERS', 'No user found, or invalid session');
                // Return an error
                $response->error('Invalid session', 400);
            }
        },
            [
                'search_customers' => 'Search for customers, and list all customers if no search is provided'
            ]
        );

        $this->post('/customers/import', function () {
            global $response;
            $this->requirePermission('add_user');

            $user = (new authentication())->get_user();
            if (!$user) {
                (new logs_o())->add('customers', 'global', 1, 0, 'IMPORT_CUSTOMER', 'No user found, or invalid session');
                $response->error('Invalid session', 400);
            }

            $data = json_decode(file_get_contents('php://input'), true);
            if (!is_array($data)) {
                $data = [];
            }

            try {
                $result = (new customer_mass_import_service())->import($data);
            } catch (\RuntimeException $throwable) {
                $statusCode = (int)$throwable->getCode();
                if ($statusCode < 400 || $statusCode > 599) {
                    $statusCode = 400;
                }

                (new logs_o())->add(
                    'customers',
                    'global',
                    1,
                    $user->id,
                    'IMPORT_CUSTOMER_FAILED',
                    $throwable->getMessage()
                );

                $response->error([
                    'message' => $throwable->getMessage(),
                ], $statusCode);
            }

            (new logs_o())->add(
                'customers',
                'global',
                1,
                $user->id,
                'IMPORT_CUSTOMER',
                'Successfully imported or created customer ' . ($result['customer_number'] ?? 'unknown')
            );

            $response->success($result);
        },
            [
                'add_user' => 'Add a user'
            ]
        );
    }

    private static function parseFunction($collection, \Closure $param): array
    {
        $result = [];
        foreach ( $collection as $item ) {
            $result[] = $param($item);
        }
        return $result;
    }

    private static function sanitizeUpstreamErrorMessage(\Throwable $throwable): string
    {
        $message = trim($throwable->getMessage());
        if ($message === '') {
            return 'Unexpected e-conomic integration error.';
        }

        $message = preg_replace('/\s+/', ' ', $message);
        if (!is_string($message)) {
            return 'Unexpected e-conomic integration error.';
        }

        return substr($message, 0, 500);
    }
}
