<?php

namespace App\Jobs;

use App\Models\Project;
use App\Models\ProjectMosaic;
use App\ProjectLogger;
use Carbon\Carbon;
use Illuminate\Bus\Batchable;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Process\Exceptions\ProcessFailedException;
use Illuminate\Process\Exceptions\ProcessTimedOutException;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Symfony\Component\Process\Process;
use Illuminate\Support\Facades\Process as ProcessNew;

/**
 *
 */
class ProjectMosiacGeneratorJob implements ShouldQueue
{
    use Batchable, Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public ProjectMosaic $mosaic;

    public $timeout = 220;

    /**
     * Create a new job instance.
     */
    public function __construct(ProjectMosaic $mosaic)
    {
        $this->mosaic = $mosaic;
    }

    /**
     * Execute the job.
     */

    /**
     * Execute the job.
     */
    public function handle(): void
    {
        $projectFolder = base_path('../');
        $project = $this->mosaic->project;

        $command = [
            sprintf('%sbuild_mosaic.sh', $projectFolder),
            sprintf('--end_date=%s', $this->mosaic->end_date->format('Y-m-d')),
            sprintf('--offset=%s', $this->mosaic->offset),
            sprintf('--data_dir=%s', $this->mosaic->project->download_path),
            sprintf('--file_name_tif=%s', basename($this->mosaic->path)),
        ];

        ProjectLogger::log($project, 'command:'. print_r($command, true));

        $currentPath = '/usr/bin:/usr/gnu/bin:/usr/local/bin:/bin:/usr/bin/Users/mfolkerts/anaconda3/bin:/Library/Apple/usr/bin';

        try {
            $process = ProcessNew::timeout(220)
                ->env(['PATH' => $currentPath.':/usr/local/Cellar/pandoc/3.1.8/bin/pandoc'])
                ->start($command, function (string $type, string $output) use ($project) {
                    ProjectLogger::log($project, $output);
                    $this->throwIfOutputContainsError($output);
                });
            $results = $process->wait();
            if ($results->successful()) {
                $this->mosaic->setStatusSuccess();
            }
        } catch (\RuntimeException|ProcessTimedOutException|ProcessFailedException $e) {
            ProjectLogger::log($project, $e->getMessage());
            $this->mosaic->setStatusFailed();
        }
    }

    /**
     * Check if the project has a mosaic for given period.
     */
    public static function handleFor(Project $project, Carbon $endDate, int $offset): NullJob|ProjectMosiacGeneratorJob
    {
        $endDate = $endDate->clone();
        ProjectLogger::log($project, "ProjectMosiacGeneratorJob::handleFor($endDate, $offset)");
        if ($project->hasInvalidMosaicFor($endDate, $offset)) {
            ProjectLogger::log($project,"ProjecMosaicGeneratorJob::handleFor(end_date: $endDate, offset: $offset): InvalidMosaic.");
            return new NullJob();
        }

        ProjectLogger::log($project, __CLASS__."::".__METHOD__."::Project->mail_day::".$project->mail_day);

        if (Carbon::parse($project->mail_day)->dayOfWeek < $endDate->dayOfWeek) {
            $endDate->next($project->mail_day);
        }


        /**
         * @var ProjectMosaic $mosaic
         */
        $mosaic = $project->createOrUpdateMosaic($endDate, $offset);
        return new self($mosaic);
    }

    private function throwIfOutputContainsError(string $output)
    {
        if (str_contains($output, 'No images available this week, empty mosaic created')) {
            throw new \RuntimeException( $output);
        }
        return true;
    }
}
