<?php

namespace OtomaticAi\Jobs;

use Exception;
use OtomaticAi\Models\SingleModeGeneration;
use OtomaticAi\Modules\ProcessAmazonModule;
use OtomaticAi\Modules\ProcessCustomFieldsModule;
use OtomaticAi\Modules\ProcessFaqModule;
use OtomaticAi\Modules\ProcessTextModule;
use OtomaticAi\Modules\ProcessImageModule;
use OtomaticAi\Modules\ProcessYoutubeModule;
use OtomaticAi\Modules\ProcessSingleModeFinalizeModule;
use OtomaticAi\Modules\ProcessToolboxModule;
use OtomaticAi\Utils\Analytics;
use OtomaticAi\Utils\Auth;
use OtomaticAi\Utils\Settings;
use OtomaticAi\Vendors\Illuminate\Support\Arr;
use OtomaticAi\Vendors\Illuminate\Support\Carbon;
use Throwable;

class GenerateSingleModeJob extends Job
{
    private SingleModeGeneration $generation;

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

    /**
     * Execute the job.
     */
    public function handle()
    {
        try {

            // verify that the generation can be publish
            if (!$this->canPublish()) {
                return;
            }

            // clear generation logs
            $this->generation->clearLogs();

            // set the generation status to pending
            $this->generation->status = "pending";
            $this->generation->generated_at = Carbon::now();
            $this->generation->save();

            // track the start of the job
            Analytics::trackEvent("generate-single-mode-start", [
                "title" => $this->generation->title,
                "type" => $this->generation->type,
                "model" => Arr::get($this->generation->modules, "models.text", 'gpt-4o-mini'),
                "image_model" => Arr::get($this->generation->modules, "models.image", 'dall-e-3'),
            ]);

            // make the generation modules
            $modules = [
                ProcessTextModule::class,
                ProcessFaqModule::class,
                ProcessImageModule::class,
                ProcessToolboxModule::class,
                ProcessAmazonModule::class,
                ProcessYoutubeModule::class,
                ProcessCustomFieldsModule::class,
                ProcessSingleModeFinalizeModule::class,
            ];

            // instantiate modules jobs
            $generationState = [
                "version" => 1,
                "status" => "running",
                "current_step" => "process_text_module",
                "steps" => Arr::keyBy(Arr::values(Arr::whereNotNull(Arr::map($modules, function ($class) {
                    if ($class::isEnabled($this->generation)) {
                        return [
                            "name" => $class::SLUG_NAME,
                            "status" => "idle",
                        ];
                    }
                }))), "name"),
                "artifacts" => [],
            ];

            // set the generation state
            $this->generation->generation_state = $generationState;
            $this->generation->save();

            // dispatch the first step
            ProcessPublicationStepJob::dispatch(["id" => $this->generation->id, "model_class" => $this->generation->getMorphClass()], 5);
        } catch (Throwable $e) {
            return $this->fail($e);
        }
    }

    private function canPublish()
    {
        // generation not started
        if ($this->generation->status !== "idle")
            return false;

        // premium or trial
        if (!Auth::isPremium()) {
            return false;
        }

        // validate openai signature
        try {
            $response = Auth::validateOpenAISignature(Settings::get("api.openai.api_key"));
            if (!Arr::get($response, "success", false)) {
                return false;
            }
        } catch (Exception $e) {
            return false;
        }

        return true;
    }

    private function fail(Throwable $error)
    {
        $this->generation->addLog("Generation failed. " . $error->getMessage(), "_default", "error", $error->getTrace());

        // track the failure of the job
        Analytics::trackEvent("generate-single-mode-failed", [
            "title" => $this->generation->title,
            "type" => $this->generation->type,
            "model" => Arr::get($this->generation->modules, "models.text", 'gpt-4o-mini'),
            "image_model" => Arr::get($this->generation->modules, "models.image", 'dall-e-3'),
            "message" => $error->getMessage(),
        ]);

        $this->generation->status = "failed";
        $this->generation->save();
    }
}
