<?php

use Mtc\Core\EmailsQueued;

// HTML Minifier
function minify_html($input) {
    return preg_replace('!\s+!', ' ', $input);
}

/**
 * __mtc_autoload_classes()
 *
 * Autoloading classes<br />
 * This is an mtc custom function so it won't screw with any 3rd party scripts
 * that also use an autoloading fuction
 *
 * @param mixed $classname
 * @return
 */
function __mtc_autoload_classes($classname) {
    $classname = strtolower($classname);

    $files[] = SITE_PATH . '/core/classes/' . $classname . '.class.php';
    $files[] = SITE_PATH . '/core/classes/class.' . $classname . '.php';

    $files[] = SITE_PATH . '/shop/classes/' . $classname . '.class.php';
    $files[] = SITE_PATH . '/shop/classes/class.' . $classname . '.php';

    $files[] = SITE_PATH . '/cms/classes/class.' . $classname . '.php';

    $found = false;
    foreach ($files as $file) {
        if (file_exists($file)) {
            require_once ($file);
            $found = true;
        }
    }

    if (!$found) {
        // Thowing exceptions will cause other autoloaders to fail. :(
        // throw new Exception("Class file $classname not found.");
    }
}

/**
 * clean_page()
 *
 * Used to clean data as it is displayed on the page.  This can be used for
 * most data.  If the HTML flag is set true double encoding will have no effect.
 *
 * @param mixed $text
 * @param bool $double_encoding When double_encode is set to false PHP will not
 * encode existing html entities.
 * @param bool $allow_html Run the string through HTML purifier so it will more
 * intelligently filter HTML strings.
 *
 * @return string clean text
 */
function clean_page($text, $double_encoding = true, $allow_html = false) {
    if ($allow_html === true) {
        $config = HTMLPurifier_Config::createDefault();
        $purifier = new HTMLPurifier($config);
        $text = $purifier->purify($text);
        return $text;
    } else {
        return htmlentities((string)$text, ENT_QUOTES, 'utf-8', $double_encoding);
    }
}

/**
 * showerrors()
 *
 * Outputs error message
 *
 * @param mixed $errors
 * @return
 */
function showerrors($errors, $type = 'error') {
    if (is_array($errors) && sizeof($errors) > 0) {
        echo '<div class="el ' . $type . ' msg">
                <ul class="' . $type . '">';
        foreach ($errors as $fieldname => $error) {
            echo '<li><a href="#' . $fieldname . '" class="jump">' . $error . "</a></li>";
        }
        echo '</ul>
                <i class="fa fa-exclamation-triangle"></i>
            </div>';
    } else {
        return false;
    }
}


/**
 * format_page()
 *
 * Used to format plaintext data as it is displayed on the page
 *
 * @param  mixed  $text
 * @return string formatted text
 */
function format_page($text) {
    return str_replace("\n", "<br>", htmlentities($text));
}

/**
 * upload_image()
 *
 * Used to validate an image upload, upload the image, resize, crop, etc.
 *
 * @param  mixed $file
 * @param  mixed $folders
 * @return mixed filename on success. false on error.
 */
function upload_image($file, $folders, $item_id = 0) {
    $uploader = \Mtc\Core\Images\ImageUploader::newInstance($folders);
    return $uploader->uploadImage($uploader->file($file), $item_id);
}


/**
 * showmsg()
 *
 * Generates output for error/success/warning messages
 *
 * @param  string $msg
 * @param  string $type
 * @param  string $path
 * @return string html output
 */
function showmsg($msg = "", $type = "", $path = "") {
    ob_start();

    $html = "";

    switch ($type) {
        case "success" :
            include ($path . "core/admin/templates/success.msg.php");
            break;
        case "warning" :
            include ($path . "core/admin/templates/warning.msg.php");
            break;
        case "error" :
            include ($path . "core/admin/templates/error.msg.php");
            break;
        default :
            return false;
    }

    $html = ob_get_clean();

    return $html;

}

/**
 * date_convert_dmy_to_db()
 *
 * Converts date from dd/mm/yyyy to yyyy-mm-dd
 *
 * @param  mixed  $date
 * @param  string $time
 * @return string|bool Date in yyyy-mm-dd format or false on failure
 */
function date_convert_dmy_to_db($date, $time = "00:00:00") {
    if (!validate_date($date)) {
        return false;
    }

    $array = explode("/", $date);

    $array[2] = substr($array[2], 0, 4);

    $d = $array[2] . "-" . $array[1] . "-" . $array[0];
    if ($time !== false) {
        $a_time = explode(":", $time);
        $d .= " " . $a_time[0] . ":" . $a_time[1] . ":" . $a_time[2];
    }

    return $d;
}

/**
 * date_convert_db_to_dmy()
 *
 * Converts date from yyyy-mm-dd to dd/mm/yyyy
 *
 * @param  mixed  $date
 * @return string date in dd/mm/yyyy format
 */
function date_convert_db_to_dmy($date, $time = false) {
    $converted_date = null;

    if ($date) {
        $holder = explode(" ", $date);
        $array = explode("-", $holder[0]);

        $converted_date = $array[2] . "/" . $array[1] . "/" . $array[0] . ($time ? ' ' . $holder[1] : '');
    }

    return $converted_date;
}

/**
 * validate_date()
 *
 * Validates that a date is in the correct format of dd/mm/yyyy
 *
 * @param  mixed $date
 * @return bool  true/false
 */
function validate_date($date) {
    // exploding the array
    $arr = explode("/", $date);

    if (sizeof($arr) == 3) {
        // first element of the array is date
        $dd = $arr[0];
        // second element is month
        $mm = $arr[1];
        // third element is year
        $yy = $arr[2];

        if ($dd == '' || !is_numeric($dd)) {
            $dd = 0;
        }
        if ($mm == '' || !is_numeric($mm)) {
            $mm = 0;
        }
        if ($yy == '' || !is_numeric($yy)) {
            $yy = 0;
        }

        if (checkdate($mm, $dd, $yy)) {
            return true;
        }
    }

    return false;
}

/**
 * clean_value()
 *
 * Used to clean output for urls
 *
 * @param  mixed  $input
 * @return string cleaned value
 */
function clean_value($input) {
    $counter = 0;
    $array = array();

    while ($counter < strlen((string)$input)) {
        //echo substr($name, $counter, 1);
        $array[$counter] = substr($input, $counter, 1);
        $counter++;
    }

    $newarray = preg_grep("([a-zA-Z0-9_-])", $array);

    $output = '';
    foreach ($newarray as $a) {
        $output .= $a;
    }

    return $output;
}

/**
 * clean_value_dot()
 *
 * Used to clean output for file names
 *
 * @param  mixed  $input
 * @return string cleaned value
 */
function clean_value_dot($input) {
    $counter = 0;

    while ($counter < strlen($input)) {
        //echo substr($name, $counter, 1);
        $array[$counter] = substr($input, $counter, 1);
        $counter++;
    }

    $newarray = preg_grep("([.a-zA-Z0-9_])", $array);
    $output = "";
    if (sizeof($newarray) > 0) {
        foreach ($newarray as $a) {
            $output .= $a;
        }
    }

    return $output;
}

/**
 * clean_value_space()
 *
 * Used to strip all non alphanumeric characters out of string
 *
 * @param  mixed  $input
 * @return string cleaned value
 */
function clean_value_space($input) {
    $counter = 0;

    $array = array();
    while ($counter < strlen($input)) {
        //echo substr($name, $counter, 1);
        $array[$counter] = substr($input, $counter, 1);
        $counter++;
    }

    $newarray = preg_grep("([a-zA-Z0-9_\s])", $array);
    $output = "";
    foreach ($newarray as $a) {
        $output .= $a;
    }

    return $output;
}

/**
 * clean_image_value()
 *
 * Alias for clean_value_dot
 *
 * @param mixed $input
 * @return
 */
function clean_image_value($input) {
    return clean_value_dot($input);
}

/**
 * get_image_size()
 *
 * Uses imageMagick to identify the image size
 *
 * @param  mixed $folder
 * @param  mixed $pic
 * @return array image sizes
 */
function get_image_size($folder, $pic) {
    $command = IMAGE_IDENTIFY . ' ' . SITE_PATH . '/' . $folder . '/' . $pic;
    //echo $command;
    $details = shell_exec($command);
    //echo $details;

    $array = explode(" ", $details);
    $resolution = $array[2];
    //echo $resolution;
    $array = explode("x", $resolution);

    $array2['width'] = $array[0];
    $array2['height'] = $array[1];

    return $array2;
}

/**
 * image_cmyk_to_rgb()
 *
 * Uses imageMagick to change the colour profile of the image
 *
 * @param mixed $folder
 * @param mixed $pic
 * @return
 */
function image_cmyk_to_rgb($folder, $pic) {
    $command = IMAGE_MOGRIFY . ' -colorspace RGB ' . SITE_PATH . '/' . $folder . '/' . $pic;
    //echo $command;
    $details = shell_exec($command);
    //echo $details;
}

/**
 * Create webp version of file
 * @param $source
 * @param int $quality
 * @return string|false Path to webp file on success, false on failure
 */
function webpImage($source, $quality = 80)
{
    // Validate source file exists
    if (!file_exists($source) || !is_readable($source)) {
        error_log("webpImage: Source file does not exist or is not readable: {$source}");
        return false;
    }

    $dir = pathinfo($source, PATHINFO_DIRNAME);
    $name = pathinfo($source, PATHINFO_FILENAME);
    $destination = $dir . DIRECTORY_SEPARATOR . $name . '.webp';

    // if webp already exists, return it
    if (file_exists($destination)) {
        return $destination;
    }

    // Escape arguments for shell safety
    $escapedSource = escapeshellarg($source);
    $escapedDest = escapeshellarg($destination);
    $escapedQuality = (int)$quality;

    // Build command with timeout (10 seconds max per image)
    // Try with 'convert' first (ImageMagick 6), fallback to 'magick' (ImageMagick 7)
    $command = sprintf(
        'timeout 10s convert %s -quality %d -strip %s 2>&1',
        $escapedSource,
        $escapedQuality,
        $escapedDest
    );

    $output = [];
    $returnCode = 0;
    exec($command, $output, $returnCode);

    // Check if conversion succeeded
    if ($returnCode === 0 && file_exists($destination)) {
        return $destination;
    }

    // Try ImageMagick 7 'magick' command if 'convert' failed
    if ($returnCode !== 0 || $returnCode === 127) {
        $command = sprintf(
            'timeout 10s magick %s -quality %d -strip %s 2>&1',
            $escapedSource,
            $escapedQuality,
            $escapedDest
        );

        $output = [];
        $returnCode = 0;
        exec($command, $output, $returnCode);

        if ($returnCode === 0 && file_exists($destination)) {
            return $destination;
        }
    }

    // Fallback to PHP GD library if ImageMagick not available
    if (function_exists('imagewebp')) {
        return webpImageGD($source, $destination, $quality);
    }

    error_log("webpImage: No WebP conversion method available. Return code: {$returnCode}. Output: " . implode(' ', $output));
    return false;
}

/**
 * Create WebP using PHP GD library (fallback)
 * @param string $source
 * @param string $destination
 * @param int $quality
 * @return string|false
 */
function webpImageGD($source, $destination, $quality = 80)
{
    $imageInfo = @getimagesize($source);
    if ($imageInfo === false) {
        error_log("webpImageGD: Could not get image info for {$source}");
        return false;
    }

    $mimeType = $imageInfo['mime'];
    $image = false;

    // Load source image based on type
    switch ($mimeType) {
        case 'image/jpeg':
            $image = @imagecreatefromjpeg($source);
            break;
        case 'image/png':
            $image = @imagecreatefrompng($source);
            // Preserve transparency
            if ($image) {
                imagealphablending($image, true);
                imagesavealpha($image, true);
            }
            break;
        case 'image/gif':
            $image = @imagecreatefromgif($source);
            break;
        default:
            error_log("webpImageGD: Unsupported image type {$mimeType} for {$source}");
            return false;
    }

    if ($image === false) {
        error_log("webpImageGD: Failed to create image resource from {$source}");
        return false;
    }

    // Convert to WebP
    $success = @imagewebp($image, $destination, $quality);
    imagedestroy($image);

    if (!$success || !file_exists($destination)) {
        error_log("webpImageGD: Failed to save WebP to {$destination}");
        return false;
    }

    return $destination;
}

/**
 * Check if a shell command is available
 * @param string $command
 * @return bool
 */
function isCommandAvailable($command)
{
    static $cache = [];

    if (isset($cache[$command])) {
        return $cache[$command];
    }

    $output = [];
    $returnCode = 0;
    exec("command -v " . escapeshellarg($command) . " 2>&1", $output, $returnCode);

    $cache[$command] = ($returnCode === 0);
    return $cache[$command];
}

/**
 * the_image_resize()
 *
 * Uses imageMagick to resize image
 *
 * @param mixed $width
 * @param mixed $heightLog::
 * @param mixed $folder
 * @param mixed $pic
 * @param bool  $forcedWidth
 * @param bool  $forcedHeight
 * @return
 */
function the_image_resize($width, $height, $folder, $pic, $forcedWidth = false, $forcedHeight = false) {
    if ($forcedWidth) {
        $width = '!' . $width;
    }
    if ($forcedHeight) {
        $height = '!' . $height;
    }
    $fullPath = SITE_PATH . "/" . $folder . "/" . $pic;
    $command = IMAGE_MOGRIFY . " -resize {$width}x{$height} '" . $fullPath . "'";
    //echo $command;echo '<br />';
    exec($command, $result);

    // Generate WebP after resize completes
    webpImage($fullPath);
}

/**
 * image_crop()
 *
 * Uses imageMagick to crop image from the top left
 *
 * @param mixed $folder
 * @param mixed $pic
 * @param mixed $width
 * @param mixed $height
 * @param mixed $x
 * @param mixed $y
 * @return
 */
function image_crop($folder, $pic, $width, $height, $x, $y) {
    $width = intval($width);
    $height = intval($height);
    $x = intval($x);
    $y = intval($y);
    $command = IMAGE_MOGRIFY . " -crop {$width}x{$height}+{$x}+{$y} +repage '" . SITE_PATH . '/' . $folder . '/' . $pic . "'";
    //echo $command;echo '<br />';
    shell_exec($command);
}

/**
 * image_crop_centercrop()
 *
 * Uses imageMagick to crop image from the center
 *
 * @param mixed $folder
 * @param mixed $pic
 * @param mixed $width
 * @param mixed $height
 * @param mixed $x
 * @param mixed $y
 * @return
 */
function image_crop_centercrop($folder, $pic, $width, $height, $x, $y) {
    $command = IMAGE_MOGRIFY . " -resize '{$width}x{$height}^' -gravity center -crop {$width}x{$height}+{$x}+{$y} +repage " . SITE_PATH . '/' . $folder . '/' . $pic;
    //echo $command;
    shell_exec($command);
}

/**
 * date_dmy_to_db()
 *
 * Alias for date_convert_dmy_to_db()
 *
 * @param  mixed  $date
 * @return string date in yyyy-mm-dd format
 */
function date_dmy_to_db($date) {
    return date_convert_dmy_to_db($date);
}

/**
 * start_tracking()
 *
 * Stores mtc. tracking information in a cookie, if set up on the website
 *
 * @return
 */
function start_tracking() {
    if (!empty($_REQUEST['ref'])) {
        setcookie("ref", $_REQUEST['ref'], time() + (2600 * 24 * 30 * 6), "/");
        $_COOKIE['ref'] = $_REQUEST['ref'];

        $parse = parse_url($_SERVER['HTTP_REFERER']);
        $se = $parse["host"];
        $raw_var = explode("&", $parse["query"]);
        foreach ($raw_var as $one_var) {
            $raw = explode("=", $one_var);
            $var[$raw[0]] = urldecode($raw[1]);
        }

        $se = explode(".", $se);
        switch ($se[1]) {
            case 'yahoo' :
                $keywords = $var['p'];
                break;
            case 'aol' :
                $keywords = $var['query'];
                break;
            default :
                $keywords = $var['q'];
        }

        if ($keywords != '') {
            setcookie("keywords", $keywords, time() + (2600 * 24 * 30 * 6), "/");
            $_COOKIE['keywords'] = $keywords;
        }

        //echo "<!-- Setting -->";
    }

}

/**
 * track()
 *
 * Sends tracking information to mtc. projects system
 *
 * @param mixed  $type
 * @param mixed  $value
 * @param string $ref
 * @param string $keywords
 * @return
 */
function track($type, $value, $ref = '', $keywords = '') {
    if ($ref == '') {
        $ref = $_COOKIE['ref'];
    }
    if ($keywords == '') {
        $keywords = $_COOKIE['keywords'];
    }
    $site = clean_value(strtolower(config('app.name')));

    if (!empty($ref)) {
        $url = "http://projects.mtcserver.com/tracking/log.php";
        $url .= "?ip=" . urlencode($_SERVER['REMOTE_ADDR']);
        $url .= "&site=" . urlencode($site);
        $url .= "&type=" . urlencode($type);
        $url .= "&campaign=" . urldecode($ref);
        $url .= "&keywords=" . urlencode($keywords);
        $url .= "&value=" . urlencode($value);

        $fh = fopen($url, 'r');

        $test = fgetc($fh);

        fclose($fh);
    }
}

/**
 * Takes date and returns converted to different format (string)
 * Author: Pawel G
 *(PHP 5 >= 5.3.0)
 *
 * @param $date
 * @param string $format
 * @param null $current_format
 * @param null $default
 * @return bool|null|string
 */
function convert_date($date, $format = 'd-m-Y H:i:s', $current_format = null, $default = null) {
    if ($date != '') {
        if ($current_format) {
            if ($formated_date = date_create_from_format($current_format, $date)) {
                return $formated_date->format($format);
            }
        } else {
            return date($format, strtotime($date));
        }
    }
    return $default;
}


/**
 * Strips out protocol at the start of URL unless it is the website itself
 *
 * @param string $url
 * @param array  $whitelist If any newsletters start having external links, add
 * them in the function call
 */
function anti_phish_redirect($url, $whitelist = []) {
    if (defined('SITE_URL')) {
        $whitelist[] = SITE_URL;
    }

    if (defined('HTTPS_SITE_URL')) {
        $whitelist[] = HTTPS_SITE_URL;
    }

    // Deny by default
    $is_whitelisted = false;

    // Whitelisted sites by logical OR
    foreach ($whitelist as $whitelisted_url) {
        if (strpos($url, $whitelisted_url) === 0) {
            $is_whitelisted = true;
        }
    }

    // This string will always be needed for absolute URLs, hence the pattern
    $evil_pattern = '://';
    $is_absolute = strpos($url, $evil_pattern);

    // Unless its absolute and not whitelisted, just use the URL
    $safe_url = $url;

    // This URL needs to be made relative
    if ($is_absolute !== false && !($is_whitelisted)) {
        // Take out the protocol
        $safe_url = substr($url, $is_absolute + strlen($evil_pattern));
        // To make it relative, take out everything before first slash
        $slash_position = strpos($safe_url, '/');
        $safe_url = substr($safe_url, $slash_position + strlen('/'));
    }

    // Finally, do the redirect
    if ($safe_url != '') {
        header('Location:' . $safe_url, true, 302);
    } else {
        echo 'The link you followed was detected to be a ';
        echo '<a href="http://en.wikipedia.org/wiki/Phishing">phishing</a> one. <br><br>';
        echo 'Please raise a ticket with us if that was not the case, mentioning the link in browser address bar.';
    }
    exit(0);
}

/**
 * Returns id value of a variable. If the variable is an object, it will return it's id property, if it's
 * an array, returns 'id' key, otherwise, assuming the id itself has been passed, will return the int value of the
 * variable.
 *
 * @author Aleksey Lavrinenko <aleksey.lavrinenko@mtcmedia.co.uk>
 *
 * @param mixed $object
 * @return int
 */
function id($object) {
    if (is_object($object)) {
        return (int)$object->id;
    } elseif (is_array($object)) {
        return (int)$object['id'];
    } else {
        // assuming the object is ID itself
        return (int)$object;
    }
}

/**
 * Check if we're in an admin page or not
 *
 * @author Kathryn Reeve <kathryn.reeve@mtcmedia.co.uik>
 *
 * @param null|callable $callback
 *
 * @return bool
 */
function isAdminSection($callback = null)
{
    $laravel_admin = false;
    if (isset($_SERVER['REQUEST_URI'])) {
        $laravel_admin = (strpos($_SERVER['REQUEST_URI'], '/admin/') === 0);
    }

    $admin_urls = [
        'generic' => strpos($_SERVER['PHP_SELF'], '/admin/') !== false,
        'core'    => strpos($_SERVER['PHP_SELF'], '/core/admin/') === 0,
        'shop'    => strpos($_SERVER['PHP_SELF'], '/shop/admin/') === 0,
        'cms'     => strpos($_SERVER['PHP_SELF'], '/cms/admin/') === 0,
        'plugins' => preg_match('#/plugins/[a-zA-Z]+/admin/?#', $_SERVER['PHP_SELF']),
        'laravel_admin' => $laravel_admin,

        // add here true value checks to Include as admin page (wp-admin?)
        // add here false value checks to Exclude pages as admin
    ];

    // allow addition or modification of the checks..
    if ($callback !== null && is_callable($callback)) {
        $admin_urls = call_user_func($callback, $admin_urls);
    }

    // filter the list, reducing list where has false
    $admin_urls = array_filter($admin_urls);

    // if all entries are false, the filtered array will have no entries
    return count($admin_urls) > 0;
}

/**
 * Used to send an email from the website
 * Removes the necessity for headers to be set.
 * Adds ability to send a copy to DEV_EMAIL
 *
 * @param string $email recipient email address
 * @param string $subject email subject
 * @param string $email_content content of the email
 * @param array $params Additional params
 * @return int whether email was sent
 * @throws Exception
 */
function email($email, $subject, $email_content, array $params = [])
{

    $default_params = [
        'from_email' => config('site.from_email'),
        'from_name' => config('app.name'),
    ];
    $params += $default_params;

    // If the queue parameter is enabled, we save the email for the background process to pick it up later.
    // Do not queue on staging / forks.
    if (!DEV_MODE && isset($params['queue']) && $params['queue']) {
        EmailsQueued::query()->create([
            'email' => $email,
            'subject' => $subject,
            'from_email' => $params['from_email'] ?: config('site.from_email'),
            'from_name' => $params['from_name'] ?: config('app.name'),
            'content' => $email_content,
            'dev_copy' => !empty($params['dev_copy']),
        ]);
        return true;
    }

    // Only send via Mailgun if enabled in settings
    if (MAILGUN_ENABLED) {
        return email_mailgun($email, $subject, $email_content, $params);
    }

    $default_params = [
        'from_email' => config('site.from_email'),
        'from_name'  => config('app.name'),
    ];

    $params += $default_params;

    /* @var $message \Mtcmedia\Mailer\SwiftMessage */
    $message = \Illuminate\Support\Facades\App::make(\Mtcmedia\Mailer\SwiftMessage::class);
    $message->setTo($email);
    $message->setSubject($subject);
    $message->setFrom($params['from_email'] ?: config('site.from_email'), $params['from_name'] ?: config('app.name'));
    $message->setReturnPath($params['from_email'] ?: config('site.from_email'));
    $message->setBody($email_content);
    if (!empty($params['reply_to'])) {
        $message->setReplyTo($params['reply_to']);
    }

    // Send a copy to dev email
    if (!empty($params['dev_copy'])) {
        $message->setBcc(DEV_EMAIL);
    }

    if (isset($params['bcc'])) {
        if (is_array($params['bcc'])) {
            foreach ($params['bcc'] as $bcc_email) $message->addBcc($bcc_email);
        } else {
            $message->addBcc($params['bcc']);
        }
    }

    if (config('app.env') === 'local') {
        $transport = new \Swift_SmtpTransport(env('MAIL_HOST'), env('MAIL_PORT'));
        $mailer = new \Swift_Mailer($transport);
        $message->setMailer($mailer);
    }

    try {
        return $message->getSent();
    } catch (Exception $exception) {
        // We got an error!
        error_log($exception->getMessage());

        return false;
    }
}

/**
 * Sends Mailgun email
 *
 * @param $email
 * @param $subject
 * @param $email_content
 * @param bool $dev_copy
 * @param array $params
 * @return bool|int
 */
function email_mailgun($email, $subject, $email_content, array $params = []) {

    $transport = (new Swift_SmtpTransport('smtp.mailgun.org', 587))
        ->setUsername(MAILGUN_SMTP_USERNAME)
        ->setPassword(MAILGUN_SMTP_PASSWORD);

    $mailer = new Swift_Mailer($transport);

    $message = (new Swift_Message($subject))
        ->setFrom(config('site.contact_email'))
        ->setTo($email)
        ->setReturnPath(config('site.contact_email'))
        ->setBody($email_content, 'text/html');

    if (!empty($params['dev_copy'])) {
        $message->setBcc(DEV_EMAIL);
    }

    if (!empty($params['reply_to'])) {
        $message->setReplyTo($params['reply_to']);
    }

    try {
        return $mailer->send($message);
    } catch (Exception $exception) {
        // We got an error!
        error_log($exception->getMessage());

        return false;
    }

}

// Laravel helpers moved into core

// check for existence to ensure this is not conflicting with laravel framework in dev dependencies
if (!function_exists('request')) {
    /**
     * Get an instance of the current request or an input item from the request.
     *
     * @param  array|string  $key
     * @param  mixed   $default
     * @return \Illuminate\Http\Request|string|array
     */
    function request($key = null, $default = null)
    {
        $request = \Illuminate\Container\Container::getInstance()->make('request');
        if (is_null($key)) {
            return $request;
        }

        if (is_array($key)) {
            return $request->only($key);
        }

        return data_get($request->all(), $key, $default);
    }
}

// check for existence to ensure this is not conflicting with laravel framework in dev dependencies
if (!function_exists('data_get')) {
    /**
     * Get an item from an array or object using "dot" notation.
     *
     * @param  mixed   $target
     * @param  string|array  $key
     * @param  mixed   $default
     * @return mixed
     */
    function data_get($target, $key, $default = null)
    {
        if (is_null($key)) {
            return $target;
        }

        $key = is_array($key) ? $key : explode('.', $key);

        while (! is_null($segment = array_shift($key))) {
            if ($segment === '*') {
                if ($target instanceof Collection) {
                    $target = $target->all();
                } elseif (! is_array($target)) {
                    return value($default);
                }

                $result = Arr::pluck($target, $key);

                return in_array('*', $key) ? Arr::collapse($result) : $result;
            }

            if (Arr::accessible($target) && Arr::exists($target, $segment)) {
                $target = $target[$segment];
            } elseif (is_object($target) && isset($target->{$segment})) {
                $target = $target->{$segment};
            } else {
                return value($default);
            }
        }

        return $target;
    }
}

function validate_csv_upload($file_name)
{
    $errors = [];
    if (empty($_FILES[$file_name])) {
        $errors[] = 'Please attach import file!';
    } else {
        $mimes = [
            'application/vnd.ms-excel',
            'text/plain',
            'text/csv',
            'text/tsv',
        ];
        if (!in_array($_FILES[$file_name]['type'], $mimes)) {
            $errors[] = 'Please upload a valid CSV! File type: ' . $_FILES[$file_name]['type'];
        }
        if ((int)$_FILES[$file_name]['error'] !== 0) {
            $errors[] = 'There was an error uploading file, please try again! Error code: ' . $_FILES[$file_name]['error'];
        }
    }
    $handle = false;
    if(empty($_FILES[$file_name]['tmp_name'])) {
        $errors[] = 'There was an error uploading file, please try again! Tmp name empty';
    } elseif (($handle = fopen($_FILES[$file_name]['tmp_name'], 'rb')) === FALSE) {
        $errors[] = 'There was an error uploading file, please try again!';
    }
    return [
        'errors' => $errors,
        'handle' => $handle,
    ];
}

function copy_image($old_location, $new_name, $resize_params) {

    $new_file_path = SITE_PATH . '/' . $resize_params['path'] . '/' . $new_name;
    $extension = end(explode('.', trim($new_file_path)));

    if (file_exists($new_file_path)) {
        unlink($new_file_path);
    }
    if (!file_exists($new_file_path)) {
        copy($old_location, $new_file_path);
        list($width, $height) = getimagesize($new_file_path);
        if ($resize_params['path'] !== 'originals' && ($width > $resize_params['width'] || $height > $resize_params['height'])) {
            $wr = $width / $resize_params['width'];
            $hr = $height / $resize_params['height'];
            $ratio = ($wr > $hr) ? $wr : $hr;

            $new_width = ceil($width / $ratio);
            $new_height = ceil($height / $ratio);

            if ($extension === 'png') {
                $src = imagecreatefrompng($new_file_path);
                $dst = imagecreatetruecolor($new_width, $new_height);
                $background = imagecolorallocate($dst , 0, 0, 0);
                imagecolortransparent($dst, $background);
                imagealphablending($dst, false);
                imagesavealpha($dst, true);
                imagecopyresampled($dst, $src, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
                imagepng($dst, $new_file_path);
            } else {
                $src = imagecreatefromjpeg($new_file_path);
                $dst = imagecreatetruecolor($new_width, $new_height);
                imagecopyresampled($dst, $src, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
                imagejpeg($dst, $new_file_path, 100);
            }
            if ($resize_params['crop']) {
                image_crop_centercrop($resize_params['path'], $new_name, $resize_params['width'], $resize_params['height'], 0, 0);
            }
        }
    }

}

if (! function_exists('template')) {
    /**
     * Get the twig template contents for the given view.
     *
     * @param  string  $view
     * @param  array   $data
     * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
     */
    function template($template = null, $data = [])
    {
        $twig = app('twig');

        if (! isset($data['page_meta'])) {
            $data['page_meta'] = [];
        }

        if (!empty($twig->getGlobals()['page_meta'])) {
            $seo_admin_data = $twig->getGlobals()['page_meta'];

            if (in_array($seo_admin_data['matched_by'], ['exact_uri'])) {
                $data['page_meta']['title'] = $seo_admin_data['title'];
                $data['page_meta']['description'] = $seo_admin_data['description'];
            }
        }

        return $twig->render($template, $data);
    }
}


if (! function_exists('array_to_csv')) {
    function array_to_csv(array $data, $separator = ",", $include_header_row = true)
    {
        $csv = '';

        $fh = fopen('php://temp', 'rw');

        if ($include_header_row) {
            fputcsv($fh, array_keys(current($data)), $separator);
        }

        // Data rows.
        foreach ($data as $row) {
            fputcsv($fh, $row, $separator);
        }

        rewind($fh);
        $csv = stream_get_contents($fh);
        fclose($fh);

        return $csv;
    }
}


if (! function_exists('init_request_values')) {
    function init_request_values(array $args) : void
    {
        $default_request_values = [];

        foreach ($args as $key => $value) {
            if (is_numeric($key)) {
                $default_request_values[$value] = null;
            } else {
                $default_request_values[$key] = $value;
            }
        }

        $_REQUEST += $default_request_values;
    }
}

if (! function_exists('redirect_if_trailing_slash')) {
    function redirect_if_trailing_slash($append_query_string = true) : void
    {
        $original_uri = $_SERVER['REDIRECT_URL'] ?? null;

        if (! $original_uri) return;

        $uri_without_trailing_slash = rtrim($original_uri, '/');

        if ($original_uri != $uri_without_trailing_slash) {

            $new_url = $uri_without_trailing_slash;

            if ($append_query_string) {
                $query_string = $_SERVER['QUERY_STRING'] ?? '';
                if ($query_string) {
                    $new_url .= "?{$query_string}";
                }
            }

            header("Location: {$new_url}", true, 301);
            exit;
        }
    }
}

if (!function_exists('getSeoSettingCachedPersistent')) {
    function getSeoSettingCachedPersistent(string $key, int $ttlSeconds = 3600 * 24)
    {
        return Cache::remember(
            "seo_setting_{$key}",
            $ttlSeconds,
            static fn() => SeoSettings::getSettingValue($key)
        );
    }
}