<?php

namespace App\Services;

use Exception;
use App\Models\Setting;
use Illuminate\Support\Str;
use App\Models\ScheduledTask;
use Illuminate\Support\Facades\Log;
use App\Models\ScheduledTaskSendingLog;
use Illuminate\Support\Facades\Storage;
use App\Exceptions\DisabledTaskException;
use App\Jobs\SendScheduledSingleReportJob;
use Illuminate\Console\Scheduling\Schedule;

class ScheduledBatchReportService
{
    private $beginTime;
    public function __construct()
    {
        $this->beginTime = now();
    }

    /**
     * Executes the batch process for sending scheduled reports.
     *
     * This method retrieves the current tasks, processes each task to generate reports,
     * and dispatches them to be sent. It also logs any failures and updates the task statuses accordingly.
     * @tag srm_schdular
     */
    public function runBatch()
    {
        $this->updateEndedTasks();
        $this->initializeTaskWorkedNow();
        deleteAllAttachments();

        $tasks = $this->getCurrentTasks();
        if(count($tasks)) {
            foreach ($tasks as $task) {

                try {
                    $this->setTaskWorkedNow($task);

                    $receivers = getReceivers($task, $task->groups);
                    $body = getBodies($task->resources->first()->resource->first(), $task->body, $receivers);

                    $this->checkBaseUrl();
                    generateReport($task->resources->first()->resource->first(), $task);
                    $report = getReportPdf($task);

                    dispatch(new SendScheduledSingleReportJob($task, $report, $receivers, $body));
                } catch(\Exception $exception) {

                    updateFailedTask(
                        $task,
                        false,
                        $exception,
                        $this->beginTime,
                        0,
                        count($receivers),
                        [],
                        'failed'
                    );


                }
            }
        }

        $this->createLog($this->beginTime, now()->toDateTimeString(), count($tasks));

    }

    /**
     * Executes a single scheduled task to generate and send a report.
     *
     * This method handles the processing of an individual task, including generating the report,
     * preparing the email body, and dispatching the report sending job.
     * If an exception occurs, it logs the failure.
     *
     * @tag srm_schdular
     */
    public function runTask(ScheduledTask $task)
    {
        if($this->checkCurrentTaskCanRun($task)) {
            throw new DisabledTaskException();
        }

        deleteAllAttachments();

        $this->setTaskWorkedNow($task);
        try {
            $receivers = getReceivers($task, $task->groups, true);
            $body = getBodies($task->resources->first()->resource->first(), $task->body, $receivers);

            $this->checkBaseUrl();
            generateReport($task->resources->first()->resource->first(), $task);
            $report = getReportPdf($task);

            dispatch(new SendScheduledSingleReportJob($task, $report, $receivers, $body, true));

        } catch(\Exception $exception) {

            updateFailedTask(
                $task,
                false,
                $exception,
                $this->beginTime,
                0,
                count($receivers),
                [],
                'failed'
            );


        }

        $this->createLog($this->beginTime, now()->toDateTimeString(), 1);

    }


    /**
     * Creates a log entry for the batch process.
     *
     * This method creates a new log entry for the task batch process, recording the time
     * the batch process was created, the time it ended, and the number of tasks processed.
     *
     * @tag srm_schdular
     */

    private function createLog($created_at, $endedAt, $taskCount)
    {

        if($this->CheckLogStatus()) {
            ScheduledTaskSendingLog::create([
                'created_at' => $created_at,
                'ended_at' => $endedAt,
                'scheduled_tasks_count' => $taskCount,
            ]);
        }
    }


    /**
     * Updates tasks whose end date has passed.
     *
     * This method updates the status of tasks that have passed their end date to "ended",
     * and sets their next sending date to null.
     *
     * @tag srm_schdular
     */
    private function updateEndedTasks()
    {
        ScheduledTask::whereDate('end_date', '<', now())->update([
            'last_status' => 'ended',
            'next_sending_date' => null
        ]);
    }

    /**
     * Marks the task as "worked now".
     *
     * This method updates the task's "worked_now" status to 1, indicating that it has been processed.
     *
     * @tag srm_schdular
     */
    private function setTaskWorkedNow($task)
    {
        $task->update(['worked_now' => 1]);
    }


    /**
     * Resets the "worked_now" status for all tasks.
     *
     * This method sets the "worked_now" field for all tasks to 0, indicating that they haven't been processed yet.
     *
     * @tag srm_schdular
     */
    private function initializeTaskWorkedNow()
    {
        ScheduledTask::query()->update(['worked_now' => 0]);
    }


    private function getCurrentTasks()
    {
        return ScheduledTask::where('next_sending_date', '<=', now())
        ->where('worked_now', 0)
        ->whereNotIn('last_status', ['stopped','ended','deleted'])->get();
    }


    /**
     * Checks if a task is eligible to run based on its status.
     *
     * This method checks if the task's last status is one of "stopped", "ended", or "deleted".
     * If so, the task is not eligible to run.
     *
     * @tag srm_schdular
     */
    private function checkCurrentTaskCanRun($task)
    {
        if(in_array($task->last_status, ['stopped','ended','deleted'])) {
            return true;
        }

        return false;
    }

    /**
     * Checks if logs for the batch sending reports task are enabled.
     *
     * This method retrieves the setting for whether batch sending logs should be recorded.
     *
     * @tag srm_schdular
     */
    private function CheckLogStatus()
    {
        return Setting::where('settings_key', 'log_sending_batch_reports_task')->first()->settings_value;
    }

    /**
     * Checks if the base URL for generating reports is configured.
     *
     * This method checks if a base URL is set in the system's settings. If not, it logs an error and throws an exception.
     *
     * @tag srm_schdular
     */
    private function checkBaseUrl()
    {
        $baseUrl = Setting::where('settings_key', 'base_url')->first()->settings_value;
        if(is_null($baseUrl)) {

            Log::error("Can't generate a report");

            throw new Exception("Can't generate a report");
        }
    }

}
