<?php

use App\Models\Auth\Verification;
use App\Models\Ecommerce\Channel\Channel;
use App\Models\Ecommerce\Product\Inventory\Inventory;
use App\Repositories\Ecommerce\Product\Barcode\BarcodeRepository;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;

if (! function_exists('modules_path')) {
    /**
     * Single translation for all locales
     */
    function modules_path(string $path = ''): string
    {
        return app_path('Modules/'.$path);
    }
}

if (! function_exists('translatable')) {
    /**
     * Single translation for all locales
     */
    function translatable(string $text): array
    {
        return collect(config('app.locales'))->map(fn ($locale) => $text)->toArray();
    }
}

if (! function_exists('removeWhiteSpace')) {
    /**
     * Remove white sapce from string
     */
    function removeWhiteSpace(string $text): string
    {
        return preg_replace('/\s+/', '', $text);
    }
}

if (! function_exists('temp_cache')) {
    /**
     * Temprory cache via array driver
     */
    function temp_cache(string|array|null $key): mixed
    {
        if (is_string($key)) {
            return cache()->get($key);
        }

        if (is_array($key)) {
            return cache()->put(
                key: $key[0],
                value: $key[1]
            );
        }

        return cache();
    }
}

if (! function_exists('sendSMS')) {
    /**
     * Send a sms
     */
    function sendSMS(string|int $phone, string|int $message): mixed
    {
        $response = Http::retry(
            times: 3,
            sleepMilliseconds: 50,
            throw: false,
            when: function (Exception $exception, PendingRequest $request) {
                Log::channel('sms_api_error')
                    ->error('Exception: ', [
                        'message' => $exception->getMessage(),
                        'line' => $exception->getLine(),
                    ]);

                return true;
            })
            ->post('http://216.250.14.144:3000/api/data', [
                'phone' => '+993'.$phone,
                'code' => $message,
            ]);

        return $response->body();
    }
}

if (! function_exists('sendSMSVerification')) {
    /**
     * Send a sms verification code
     *
     * @return \App\Models\Verification | null
     */
    function sendSMSVerification(string|int $phone_number): ?Verification
    {
        /* for apple testing */
        $phone_code = ($phone_number == '61126667') ? 77777 : rand(10000, 99999);

        $verification = Verification::where(['username' => $phone_number])->first();
        $verification
            ? $verification->update(['code' => $phone_code])
            : Verification::create(['username' => $phone_number, 'code' => $phone_code]);

        sendSMS($phone_number, 'Tassyklaýyş belgi: '.$phone_code);

        return $verification;
    }
}

if (! function_exists('randomHex')) {
    /**
     * Generate random hex
     */
    function randomHex(): string
    {
        $chars = 'ABCDEF0123456789';
        $color = '#';
        for ($i = 0; $i < 6; $i++) {
            $color .= $chars[rand(0, strlen($chars) - 1)];
        }

        return $color;
    }
}

if (! function_exists('phoneMaskFormat')) {
    /**
     * Phone number mask
     */
    function phoneMaskFormat(): string
    {
        return '+(\\9\\93)-99-99-99-99';
    }
}

if (! function_exists('unmask_phone')) {
    /**
     * Unmask phone from TM code +(993)-6x-xx-xx-xx to 6xxxxxxx
     */
    function unmask_phone(string|int|float $phone): string
    {
        return str_replace(['+(993)', '-'], '', $phone);
    }
}

if (! function_exists('mask_phone')) {
    /**
     * Mask phone for TM code from 6xxxxxxx to +(993)-6x-xx-xx-xx
     */
    function mask_phone(string|int|float $phone): string
    {
        // Split the number into an array of every two digits
        $chunks = array_chunk(str_split($phone, 2), 1);

        // Collapse the array chunks into a string with dashes
        return '+(993)-'.implode('-', array_map('implode', $chunks));
    }
}

if (! function_exists('tmpostChannel')) {
    /**
     * Default channel
     *
     * @return \App\Models\Shop\Channel
     */
    function tmpostChannel(): Channel
    {
        Cache::rememberForever('tmpostChannel', fn () => Channel::tmpostDefault());

        return Cache::get('tmpostChannel');
    }
}

if (! function_exists('tmpostDefaultInventory')) {
    /**
     * Default inventory id
     */
    function tmpostDefaultInventory(): mixed
    {
        Cache::rememberForever('tmpostDefaultInventory', fn () => Inventory::tmpostDefault());

        return Cache::get('tmpostDefaultInventory');
    }
}

if (! function_exists('round_up')) {
    /**
     * Round up the float
     */
    function round_up(string|int|float $number, int $precision = 2): float
    {
        $fig = (int) str_pad('1', $precision, '0');

        return ceil($number * $fig) / $fig;
    }
}

if (! function_exists('routeName')) {
    /**
     * Current route name
     */
    function routeName(): ?string
    {
        return Route::currentRouteName();
    }
}

if (! function_exists('routeIs')) {
    /**
     * Check if current route matches with given datas
     */
    function routeIs(string|array $name): bool
    {
        return is_string($name)
                ? $name === routeName()
                : in_array(routeName(), $name);
    }
}

/**
 * Check if route is product related
 */
function routeIsProductRelated(): bool
{
    return routeIs([
        'web.categories.products',
        'web.brands.products',
        'web.collections.products',
        'web.entrepreneurs.show',
        'web.search.index',
    ]);
}

if (! function_exists('keyValueExistsInArray')) {
    /**
     * Check "key-value" exists in array
     *
     * @param  int  $key
     * @param  int  $value
     */
    function keyValueExistsInArray(array $datas, string|int $key, string|int $value): bool
    {
        foreach ($datas as $data) {
            if (isset($data[$key]) && $data[$key] === $value) {
                return true;
            }
        }

        return false;
    }
}

if (! function_exists('productTaxForCategory')) {
    /**
     * Product tax for categories it has been related
     * As of now, the highest category tax is taken
     */
    function productTaxForCategory(array|Collection $categories): int
    {
        return DB::table('categories')
            ->whereIntegerInRaw('id', $categories)
            ->select(DB::raw('MAX(tax_percentage::integer) as tax'))
            ->pluck('tax')[0] ?? 1;
    }
}

if (! function_exists('validateCommaSeperated')) {
    /**
     * Validates a comma-separated string of fields.
     *
     * - Validates the format of each field (alphanumeric or underscore).
     * - Optionally checks fields against a model's fillable property.
     *
     * @param  string|null  $value  The comma-separated string to validate.
     * @param  string|null  $model  The model class to check fields against (optional).
     * @return string[] An array of validated fields.
     */
    function validateCommaSeperated(?string $value, mixed $model = null): array
    {
        if (is_null($value)) {
            return [];
        }

        $values = explode(',', removeWhiteSpace($value));
        $validated = [];

        $fields = [];
        if (! is_null($model)) {
            $fields = (new $model)->getFillable();
        }

        foreach ($values as $value) {
            if (empty($value) || is_numeric($value)) {
                continue;
            }

            if (! validator(data: ['key' => $value], rules: ['key' => ['alpha_dash:ascii']])->fails()) {
                if (! empty($fields)) {
                    if (in_array($value, $fields)) {
                        $validated[] = $value;
                    }

                    continue;
                }

                $validated[] = $value;
            }
        }

        return $validated;
    }
}

if (! function_exists('orderAdminNumber')) {
    /**
     * Order admin phone number
     */
    function orderAdminNumber(): int
    {
        return 61126667;
    }
}

if (! function_exists('barcodeGeneratorRoute')) {
    /**
     * Barcode generator route
     */
    function barcodeGeneratorRoute(): string
    {
        return BarcodeRepository::imageGeneratorRoute();
    }
}

if (! function_exists('calculateProductPriceAmount')) {
    /**
     * Calculate product price amount
     */
    function calculateProductPriceAmount(int|float $price, int $tax): float
    {
        return round_up(($price / (100 - $tax)) * 100);
    }
}

/**
 * Halkbank credentials
 *
 * @return int|string|array{username: int|string, password: string}
 */
function halkbankCredentials(string $key = ''): int|string|array
{
    return match ($key) {
        'username' => 516122500260,
        'password' => 'MrZsO9wfgWOBjf4',
        default => [
            'username' => 516122500260,
            'password' => 'MrZsO9wfgWOBjf4',
        ]
    };
}

/**
 * Create halkbank order
 *
 * @param  string  $price
 * @return array{status: string, url: string|null}
 */
function createHalkbankOrder($price = 123): array
{
    $orderNumber = date('dmyHis');

    $paymentResponse = Http::get('https://mpi.gov.tm/payment/rest/register.do', [
        'orderNumber' => $orderNumber,
        'amount' => $price,
        'currency' => 934,
        'language' => 'ru',
        'userName' => halkbankCredentials('username'),
        'password' => halkbankCredentials('password'),
        'returnUrl' => route('online-payment-store'),
        'pageView' => 'DESKTOP',
        'description' => 'MM.COM.TM',
    ])->onError(function ($response) {
        Log::error('Payment error', [
            'response' => [
                'body' => $response->body(),
            ],
        ]);
    });

    if ($paymentResponse->failed()) {
        return [
            'status' => 'failed',
            'url' => '',
            'orderId' => '',
        ];
    }

    return [
        'status' => 'success',
        'url' => $paymentResponse['formUrl'],
        'orderId' => $paymentResponse['orderId'],
    ];
}

/**
 * Original quality :D
 */
function convertToOriginalFormat(int|float|string $apiPrice): string
{
    $originalPrice = intval($apiPrice) / 100;

    return number_format($originalPrice, 2, '.', '');
}
