<?php

use App\Models\User;
use App\Models\Setting;
use App\Models\Resource;
use Illuminate\Support\Facades\Log;
use App\Services\ScheduledReportService;
use App\Http\Controllers\Auth\LoginController;


/**
 * Generates a report by making a request to an external URL.
 *
 * This function attempts to generate a report by making a cURL request to either the report URL obtained
 * through the `getReportUrl()` method of the `Resource` object or an internal Docker-based URL. The function
 * sets headers for internal authentication using the shared key and task title. It returns the response if
 * the report is successfully generated, and logs an error if it fails.
 *
 * @tag srm_schdular
 */

if (!function_exists("generateReport")) {

    function generateReport(Resource $report, $task)
    {
        if (strtolower(getInstallationMethod()) == "composer") {
            $url = $report->getReportUrl() . "?export=pdf1&save=1";
        } else {
            $url = getInternalDocker() . getReportPath($report->url)  . "?export=pdf1&save=1";
        }

        $ch = curl_init();

        try {
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                'INTERNAL-KEY: ' . getSharedKey(),
                'TASK-NAME: ' . $task->title
            ]);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_FAILONERROR, false);

            $response = curl_exec($ch);
            if ($response === false) {
                $error = curl_error($ch);
                Log::error("cURL error: $error");

                throw new Exception("cURL error: $error");
            }

            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            if ($httpCode == 200 && empty($response)) {
                return $response;
            } else {
                Log::error("Error: Can't generate report. HTTP Code: $httpCode. Response: $response");
                throw new Exception("Error: Can't generate report. HTTP Code: $httpCode. Response: $response");
            }
        } finally {
            curl_close($ch);
        }
    }
}


/**
 * Retrieves the shared key from the settings table.
 *
 * This function fetches the shared key value stored in the settings table. It is used to retrieve
 * a predefined shared key that may be needed for authentication, security, or other related tasks.
 *
 * @tag srm_schdular
 */
if (!function_exists("getSharedKey")) {
    function getSharedKey()
    {
        return Setting::where('settings_key', 'shared_key')->first()->settings_value;
    }
}


/**
 * Generates the file path for the report PDF.
 *
 * This function constructs the full file path for a report PDF based on the task's title.
 * It checks if the directory for storing the report exists, and if not, it creates it.
 * The report file name is derived by removing spaces from the task title and appending a `.pdf` extension.
 *
 * @tag srm_schdular
 */
if (!function_exists("getReportPdf")) {

    function getReportPdf($task)
    {

        $reportPath =  getAttachmentPath();
        $reportName = str_replace(' ', '', $task->title).'.pdf';

        if (!is_dir($reportPath)) {
            @mkdir($reportPath, 0775, true);
        }

        return $reportPath  . $reportName;
    }
}


/**
 * Deletes all PDF attachments from the specified directory.
 *
 * This function deletes all PDF files found in the directory specified by the `getAttachmentPath` function.
 * It uses the `glob` function to find all `.pdf` files in that directory and removes them using the `unlink` function.
 *
 * @tag srm_schdular
 */
if (!function_exists("deleteAllAttachments")) {

    function deleteAllAttachments()
    {
        $attachments = glob(getAttachmentPath() . '*.pdf');
        foreach ($attachments as $attachment) {
            if (is_file($attachment)) {
                unlink($attachment);
            }
        }

    }
}

/**
 * Deletes the task's PDF attachment.
 *
 * This function deletes the PDF attachment associated with the given task by constructing the
 * file path using the task title (with spaces removed) and the attachment path retrieved
 * from the `getAttachmentPath` function. If the file exists, it is removed using the `unlink` function.
 *
 * @tag srm_schdular
 */
if (!function_exists("deleteTaskAttachment")) {

    function deleteTaskAttachment($task)
    {
        $attachment = getAttachmentPath() . str_replace(' ', '', $task->title) .'.pdf';
        if (is_file($attachment)) {
            unlink($attachment);
        }

    }
}

/**
 * Retrieves the path for storing PDF attachments.
 *
 * This function constructs the file path for PDF attachments by combining the base application path
 * and the value stored in the `pdf_attachments` setting in the database. It trims any leading slashes
 * from the setting value to ensure the path is correctly formed.
 *
 * @tag srm_schdular
 */
if (!function_exists("getAttachmentPath")) {
    function getAttachmentPath()
    {
        return base_path() ."/". ltrim(Setting::where('settings_key', 'pdf_attachments')->first()->settings_value, "/") ;
    }
}


/**
 * Handles the successful completion of a scheduled task.
 *
 * This function updates the task's status, next sending date, retry count, and other attributes
 * upon successful execution. It also logs the task's success details in the task history.
 *
 * @tag srm_schdular
 */
if (!function_exists("updateSuccessTask")) {


    function updateSuccessTask($task, $manual, $beginTime, $totalSent, $totalFailed, $sentIds)
    {
        $nextSendingTime = $manual
        ? $task->next_sending_date
        : ScheduledReportService::recaluclateNextSendingDate($task);
        // dd($totalSent);
        $task->update([
            'last_sending_datetime' => now()->toDateTimeString(),
            'last_status' => 'success',
            'next_sending_date' => $nextSendingTime,
            'retry_count' => 0,
            'recieved_users' => $sentIds,
            'worked_now' => 0
        ]);

        $task->taskHistory()->create([
            'start_sending_date' => $beginTime,
            'end_sending_date' => now()->toDateTimeString(),
            'error_message' => null,
            'status' => 'success',
            'next_sending_date' => $nextSendingTime,
            'total_sent' => $totalSent,
            'total_failed' => $totalFailed
        ]);

    }

}


/**
 * Handles the failure of a scheduled task.
 *
 * This function updates the task's status, retry count, next sending date, and other related attributes
 * when a task fails during execution. It also logs the task's failure details in the task history.
 *
 * @tag srm_schdular
 */
if (!function_exists("updateFailedTask")) {
    function updateFailedTask(
        $task,
        $manual,
        $error,
        $beginTime,
        $totalSent,
        $totalFailed,
        $sendIds,
        $status
    ) {
        $errorMsg = buildErrorMsg($error->getMessage(), getExceptionMethod($error), $error->getLine(), $error->getTraceAsString());

        if ($task->retry_count >= getMailRetriesCount()) {
            $retryCount = 0;

            $nextSendingTime = ScheduledReportService::recaluclateNextSendingDate($task);

            $sendIds = null;

        } else {
            $retryCount = $task->retry_count + 1;

            $nextSendingTime = $task->next_sending_date;

            if (in_array($task->last_status, ['incomplete','failed'])) {
                $task->recieved_users = !is_null($task->recieved_users) && is_array($task->recieved_users)
                ? $task->recieved_users
                : [];

                $sendIds = is_array($sendIds) && count($sendIds) > 0
                ? array_merge($task->recieved_users, $sendIds)
                : $task->recieved_users;
            }

        }

        if ($manual) {
            $nextSendingTime = $task->next_sending_date;
        }

        $task->update([
            'last_sending_datetime' => now()->toDateTimeString(),
            'last_status' => $status,
            'recieved_users' => $sendIds,
            'retry_count' => $retryCount,
            'next_sending_date' => $nextSendingTime,
            'worked_now' => 0
        ]);

        $task->taskHistory()->create([
            'start_sending_date' => $beginTime,
            'end_sending_date' => now()->toDateTimeString(),
            'error_message' => $errorMsg,
            'status' => $status,
            'next_sending_date' => $task->next_sending_date,
            'total_sent' => $totalSent,
            'total_failed' => $totalFailed
        ]);

    }
}

/**
 * Update the next sending time for a task.
 *
 * This function recalculates and updates the `next_sending_date` for the given scheduled task
 * using the `ScheduledReportService::recaluclateNextSendingDate` method.
 *
 * @tag srm_schdular
 */
if (!function_exists("updateTaskSendingTime")) {

    function updateTaskSendingTime($task)
    {
        $task->update([
            'next_sending_date' => ScheduledReportService::recaluclateNextSendingDate($task)
        ]);
    }
}


/**
 * Retrieve the mail retries count.
 *
 * This function fetches the configured number of retries for sending emails from the application settings.
 * If the setting is not found, it returns a default value.
 *
 * @tag srm_schdular
 */
if (!function_exists("getMailRetriesCount")) {

    function getMailRetriesCount($default = 3)
    {
        return !is_null(Setting::where('settings_key', 'mail_retry_count')->first())
        ? Setting::where('settings_key', 'mail_retry_count')->first()->settings_value
        : $default;
    }

}


/**
 * Build a detailed error message.
 *
 * This function generates a comprehensive error message string, including the method name,
 * line number, exact error message, and stack trace. It is used to provide detailed
 * debugging information for error handling.

 * @tag srm_schdular
 */
if (!function_exists("buildErrorMsg")) {

    function buildErrorMsg($errorMsg, $method, $line, $stackTrace)
    {
        return "The task failed at method: $method , Line: $line , Exact error message: $errorMsg ,  stack trace : $stackTrace";
    }
}


/**
 * Get the URL for a given resource based on its type.
 *
 * This function determines the resource type and generates the corresponding URL for
 * "Blank Reports," "Charts," or "KPIs / Metrics." It ensures that the URLs are either absolute
 * or relative based on whether the application is running in the console or web environment.
 *
 * @tag srm_schdular
 */
if (!function_exists("getResourceUrl")) {
    function getResourceUrl($resource)
    {
        switch ($resource->getResourceType()) {
            case 'Blank Reports':
                $url = rtrim(getBaseUrl(), '/') . '/reports/'. $resource->id;
                return makeLineHyperLink($url) ;
                break;
            case 'Charts':
                $url = rtrim(getBaseUrl(), '/') . '/charts/'. $resource->id;

                return makeLineHyperLink($url) ;
                break;
            case 'KPIs / Metrics':
                $url = rtrim(getBaseUrl(), '/') . '/metrics/'. $resource->id;

                return makeLineHyperLink($url);
                break;
            default:
                break;
        }
    }
}


/**
 * Generate a hyperlink for a given URL.
 *
 * This function creates an HTML anchor tag (`<a>`) with the provided URL,
 * making it clickable in rendered HTML content.
 *
 * @tag srm_schdular
 */
if (!function_exists("makeLineHyperLink")) {
    function makeLineHyperLink($url)
    {
        return '<a href="'.$url.'">'.$url.'</a>';
    }
}


/**
 * Generate a descriptive statement for a given resource.
 *
 * This function creates a string representation of the resource type, including
 * its name and a hyperlink to its URL, based on the type of resource.
 *
 * @tag srm_schdular
 */
if (!function_exists("getResourceStatement")) {
    function getResourceStatement($resource)
    {
        switch ($resource->getResourceType()) {
            case 'Blank Reports':
                return $resource->name . ' report : '. getResourceUrl($resource);
                break;
            case 'Charts':
                return  $resource->name . ' chart : '. getResourceUrl($resource);
                break;
            case 'KPIs / Metrics':
                return $resource->name . ' metric : '. getResourceUrl($resource);
                break;
            default:
                break;
        }
    }
}


/**
 * Retrieve the internal Docker host URL.
 *
 * This function returns the base URL used to access services running within the Docker container.
 * It is intended for internal use within the application to interact with Dockerized services.
 *
 * @tag srm_schdular
 */
if (!function_exists("getInternalDocker")) {
    function getInternalDocker()
    {
        return "http://localhost";
    }
}
