<?php

use App\Enums\AttachmentTypeEnum;
use App\Enums\ExternalAccountDirectionEnum;
use App\Enums\PaymentGateWayEnum;
use App\Libs\Utility\Utility;
use App\Models\User;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Enums\LogLevelEnum;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Intervention\Image\Facades\Image;
use libphonenumber\PhoneNumberUtil;
use libphonenumber\PhoneNumber;
use ProtoneMedia\LaravelFFMpeg\Support\FFMpeg;

if (!function_exists('single_space')) {
    function single_space(string $input): string
    {
        return preg_replace('!\s+!', ' ', $input);
    }
}

if (!function_exists('remove_space')) {
    function remove_space(string $value, string $replaceWith = ""): array|string|null
    {
        return preg_replace("/\s+/", $replaceWith, $value);
    }
}

if (!function_exists('api_response')) {
    function api_response(int $code, string $message = null, $data = null): \Illuminate\Http\Response|\Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory
    {
        return response([
            'code' => $code,
            'message' => $message,
            'data' => $data
        ]);
    }
}

if (!function_exists('log_level')) {
    function log_level(string $message, LogLevelEnum $level, array $data = []): void
    {
        if ($level === LogLevelEnum::emergency) {
            Log::emergency($message, $data);
        }

        if ($level === LogLevelEnum::alert) {
            Log::alert($message, $data);
        }

        if ($level === LogLevelEnum::critical) {
            Log::critical($message, $data);
        }

        if ($level === LogLevelEnum::error) {
            Log::error($message, $data);
        }

        if ($level === LogLevelEnum::warning) {
            Log::warning($message, $data);
        }

        if ($level === LogLevelEnum::notice) {
            Log::notice($message, $data);
        }

        if ($level === LogLevelEnum::info) {
            Log::info($message, $data);
        }

        if ($level === LogLevelEnum::debug) {
            Log::debug($message, $data);
        }
    }
}

if (!function_exists('log_debug')) {
    function log_debug(Exception $exception = null, string $prefix = null, array $data = [], LogLevelEnum $level = LogLevelEnum::info): void
    {
        $message = $exception !== null
            ? sprintf(
                'FILE::%s, LINE::%s, MESSAGE:: %s',
                $exception->getFile(),
                $exception->getLine(),
                $exception->getMessage()
            )
            : '';

        if ($prefix !== null) {
            log_level($prefix . ' ::: ' . $message, $level, $data);
        } else {
            log_level($message, $level, $data);
        }
    }
}

if (!function_exists('otp_code')) {
    function otp_code(string $telephone = null)
    {
        if ($telephone == config('torryme.constants.default_demo_telephone')) {
            return config('torryme.constants.default_demo_otp');
        }

        $generator = "0123456789";
        $result = "";
        $length = config('torryme.constants.otp_length');

        for ($i = 1; $i <= $length; $i++) {
            $result .= substr($generator, (rand() % (strlen($generator))), 1);
        }

         return $result;
    }
}

if (!function_exists('unique_file_name')) {
    function unique_file_name(string $prefix, string $extension): string
    {
        return uniqid(strtolower($prefix) . '_') . '_' . now()->timestamp . $extension;
    }
}

if (!function_exists('check_doc_path')) {
    function check_doc_path(string $basePath): void
    {
        if (!File::isDirectory($basePath)) {
            File::makeDirectory($basePath, 0777, true);
        }
    }
}

if (!function_exists('upload_file_system')) {
    function upload_file_system(string $type, string $basePath, UploadedFile $file): ?string
    {
        if (Utility::isImage($file)) {
            return upload_image($type, $basePath, $file);
        }

        return upload_file($type, $basePath, $file);
    }
}

if (!function_exists('upload_image')) {
    function upload_image(string $type, string $basePath, UploadedFile $file): ?string
    {
        $storageOption = config('torryme.storage_option');
        $result = null;

        try {
            check_doc_path($basePath);
            $fileName = unique_file_name(
                $type,
                config('torryme.constants.default_image_extension')
            );

            // Save original image
            $originalImage = Image::make($file);
            // Finally
            Storage::disk($storageOption)->put(
                sprintf('%s/%s', $basePath, $fileName),
                $originalImage->encode(
                    mb_strtolower(config('torryme.constants.image_encoding')),
                    90
                )->getEncoded()
            );

            $result = $fileName;
        } catch (\Exception $e) {
            log_debug(exception: $e, prefix: 'upload_image');
        }

        return $result;
    }
}

if (!function_exists('upload_file')) {
    function upload_file(string $documentType, string $basePath, UploadedFile $file): ?string
    {
        $storageOption = config('torryme.storage_option');
        $result = null;

        try {
            check_doc_path($basePath);
            $fileName = unique_file_name(
                $documentType,
                "." . $file->getClientOriginalExtension(),
            );

            // Save original file
            if ($file->storeAs($basePath, $fileName, $storageOption)) {
                $result = $fileName;
            }
        } catch (\Exception $e) {
            log_debug(exception: $e, prefix: 'upload_file');
        }

        return $result;
    }
}

if (!function_exists('generate_wallet_number')) {
    function generate_wallet_number(string $prefix): string
    {
        $length = config('torryme.constants.wallet_number_length');
        $additional = 1;
        $suffixLength = $length - $additional - strlen($prefix);

        $str = '' . $prefix;
        if (strlen($str) >= $suffixLength) {
            return sprintf("W%s", $str);
        }

        return sprintf("W%s", str_repeat('0', $suffixLength) . $str);
    }
}

if (!function_exists('random_user_name')) {
    function random_user_name(string $base): string
    {
        $pattern = " ";
        $secondPart = strstr(strtolower($base), $pattern, false);
        $firstPart = strstr(strtolower($base), $pattern, true);
        $firstPart = substr(
            $firstPart,
            0,
            rand(1, strlen($firstPart) > 5 ? strlen($firstPart) / 2 : strlen($firstPart) - 2)
        );
        $nrRand = rand(0, 100);

        return trim($firstPart) . '.' . trim($secondPart) . trim($nrRand);
    }
}

if (!function_exists('generate_user_name')) {
    function generate_user_name(string $base, int $max): array
    {
        $result = [];
        $i = 1;

        while ($i <= $max) {
            do
                $userName = remove_space(random_user_name($base), "_");
            while (User::userNameExist($userName));

            $result[] = $userName;
            $i++;
        }

        return array_unique($result);
    }
}

if (!function_exists('build_storage_file_url')) {
    function build_storage_file_url($resourceId, string $type, string $file): string
    {
        return route('serve.doc', [
            'resourceId' => $resourceId, 'q' => $type, 'file' => $file
        ]);
    }
}

if (!function_exists('absolute_doc_path')) {
    function absolute_doc_path($modelInstance, string $docName, string $prefix): ?string
    {
        if (empty($docName)) {
            return null;
        }

        if ($modelInstance === null) {
            return null;
        }

        $docPath = sprintf('%s/%s', $prefix . $modelInstance->{'id'}, $docName);
        return sprintf(config('torryme.paths.docs'), $docPath);
    }
}

if (!function_exists('transaction_reference')) {
    function transaction_reference(string $transactionType): string
    {
        $generator = "0123456789";
        $code = "";
        $length = config('torryme.constants.transaction_reference_length');

        for ($i = 1; $i <= $length; $i++) {
            $code .= substr($generator, (rand() % (strlen($generator))), 1);
        }

        return $transactionType . "" . $code;
    }
}

if (!function_exists('get_payment_gateway')) {
    function get_payment_gateway(string $paymentGateWay): string
    {
        return match ($paymentGateWay) {
            config("torryme.payment_gateways.momo") => PaymentGateWayEnum::momo->value,
            config("torryme.payment_gateways.orange_money") => PaymentGateWayEnum::orangeMoney->value,
            config("torryme.payment_gateways.eu_money") => PaymentGateWayEnum::euMoney->value,
            config("torryme.payment_gateways.paypal") => PaymentGateWayEnum::payPal->value,
            config("torryme.payment_gateways.visa") => PaymentGateWayEnum::visa->value,
            config("torryme.payment_gateways.master_card") => PaymentGateWayEnum::masterCard->value,
            default => PaymentGateWayEnum::internal->value,
        };
    }
}

if (!function_exists('get_external_account_direction')) {
    function get_external_account_direction(string $direction): ?string
    {
        return match ($direction) {
            config("torryme.externL_account_direction.in") => ExternalAccountDirectionEnum::in->value,
            config("torryme.externL_account_direction.out") => ExternalAccountDirectionEnum::out->value,
            default => null,
        };
    }
}

if (!function_exists('upload_file_type')) {
    function upload_file_type(UploadedFile $uploadedFile): AttachmentTypeEnum
    {
        $attachmentType = AttachmentTypeEnum::document;

        if (Utility::isImage($uploadedFile)) {
            $attachmentType = AttachmentTypeEnum::image;
        }

        if (Utility::isAudio($uploadedFile)) {
            $attachmentType = AttachmentTypeEnum::audio;
        }

        if (Utility::isVideo($uploadedFile)) {
            $attachmentType = AttachmentTypeEnum::video;
        }

        if (Utility::isPdf($uploadedFile)) {
            $attachmentType = AttachmentTypeEnum::pdf;
        }

       if (Utility::isPdf($uploadedFile)) {
          $attachmentType = AttachmentTypeEnum::pdf;
       }

        return $attachmentType;
    }
}

if (!function_exists('count_pdf_page')) {
    function count_pdf_page(string $path): ?int
    {
        if (Str::endsWith($path, '.pdf')) {
            Log::info($path);
            try {
                $pdfText = file_get_contents($path);

                return preg_match_all("/\/Page\W/", $pdfText, $dummy);
            } catch (\Exception $exception) {
                log_debug($exception, 'count_pdf_page');
            }
        }

        return null;
    }
}

if (!function_exists('file_duration')) {
    function file_duration(string $path): int
    {
       // TODO Explore intervention io
        return 0;
    }
}

if (!function_exists('build_share_post_url')) {
    function build_share_post_url(int $postId): string
    {
        // TODO Encrypt post id
        return route('posts.share', ['q' => $postId]);
    }
}

if (!function_exists('build_user_profile_url')) {
    function build_user_profile_url(int $userId): string
    {
        return route('users.profile-url', ['userId' => $userId]);
    }
}

if (!function_exists('generate_coupon_code')) {
    function generate_coupon_code(string $couponType, $couponId): string
    {
        $generator = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        $code = "";
        $length = config('torryme.constants.coupon_code_length');

        for ($i = 1; $i <= $length; $i++) {
            $code .= substr($generator, (rand() % (strlen($generator))), 1);
        }

        return $couponType . $code . $couponId;
    }
}

if (!function_exists('parse_phone_number')) {
    function parse_phone_number($phoneNumber, string $countryIsoCode = null): ?PhoneNumber
    {
        $phoneUtil = PhoneNumberUtil::getInstance();

        try {
            $phoneNumberProto = $phoneUtil->parse($phoneNumber, $countryIsoCode);
            if ($phoneNumberProto) {
                return $phoneNumberProto;
            }
        } catch (Exception $e) {
            log_debug($e, "Helpers::parse_phone_number: Unable to parse " . $phoneNumber);
        }

        return null;
    }
}

if (!function_exists('default_paginator_format')) {
    function default_paginator_format($lastPage, $total, $currentPage, string $resultKey, $data): array
    {
        return array(
            "last_page" => $lastPage,
            "total" => $total,
            "current_page" => $currentPage,
            $resultKey => $data
        );
    }
}

if(!function_exists('convert_datetime_to_utc')) {
    function convert_datetime_to_utc(string $dateTime, $requestTimeZone): bool|Carbon
    {
        $timeZone = !empty($requestTimeZone) ? $requestTimeZone : config("torryme.constants.default_time_zone");
        $date = Carbon::createFromFormat('Y-m-d H:i:s', $dateTime, $timeZone);
        $date->setTimezone('UTC');

        return $date;
    }
}

if(!function_exists('generate_uuid')) {
   function generate_uuid(string $tableName, string $column = 'uuid'): string
   {
      do {
         $uuid = Str::uuid()->toString();
      } while (DB::table($tableName)->where($column, $uuid)->exists());

      return $uuid;
   }
}

if(!function_exists('build_community_url')) {
   function build_community_url(int $communityId): string
   {
      return route('community.share', ['c' => $communityId]);
   }
}

if(!function_exists('extract_video_thumbnail')) {
   function extract_video_thumbnail(string $path, string $fileName, $frameSeconds = 0.1): ?string
   {
      $storageOption = config('torryme.storage_option');

      if(Storage::disk($storageOption)->exists($path)) {
         $resultPath = sprintf(
            config('torryme.paths.thumbnails'),
            $fileName,
         );

         $ffmpeg = FFMpeg::fromDisk($storageOption)->open($path);

         if(is_int($frameSeconds)) {
            $ffmpeg = $ffmpeg->getFrameFromSeconds($frameSeconds);
         }

         if(is_string($frameSeconds)) {
            $ffmpeg = $ffmpeg->getFrameFromString('thumbnail');
         }

         $ffmpeg->export()->save($resultPath);
         return $resultPath;
      }

      return null;
   }
}

if(!function_exists('replace_file_extension')) {
   function replace_file_extension(string $fileName, string $extension): ?string
   {
      return preg_replace('/\.\w+$/', '', $fileName) . $extension;
   }
}

if(!function_exists('file_metadata')) {
   function file_metadata(string $fileName): array
   {
      $result = [];

      try {
         $storageOption = config('torryme.storage_option');
         $ffmpeg = FFMpeg::fromDisk($storageOption)->open($fileName);

         $result['duration'] = $ffmpeg->getDurationInSeconds();
         $dimensions = $ffmpeg->getVideoStream()->getDimensions();
         $result['dimensions'] = [
            'height' => $dimensions->getHeight(),
            'width' => $dimensions->getWidth(),
         ];
      } catch (\Exception $exception) {
         log_debug($exception, 'RealtimeMessageAttachment::metadata');
      }

      return $result;
   }
}

