<?php

namespace OtomaticAi\Modules;

use Exception;
use OtomaticAi\Models\Contracts\Publishable;
use OtomaticAi\Models\Presets\Preset;
use OtomaticAi\Modules\Contracts\Module as ModuleContract;
use OtomaticAi\Vendors\Illuminate\Support\Arr;
use OtomaticAi\Vendors\Illuminate\Support\Str;

class ProcessWordpressModule extends Module implements ModuleContract
{
    const SLUG_NAME = "process_wordpress_module";

    /**
     * Execute the job.
     * 
     * @return void
     * @throws Exception
     */
    public function handle(): void
    {
        // verify that the job is runnable
        if (!$this->isRunnable()) {
            return;
        }

        // perform automatic tags
        $this->handleAutomaticTags();

        // perform automatic categories
        $this->handleAutomaticCategory();

        // perform seo title
        $this->handleSeoTitle();

        // perform seo description
        $this->handleSeoDescription();
    }

    /**
     * Generate automatic tags
     *
     * @return void
     */
    private function handleAutomaticTags(): void
    {
        // verify that the automatic tags are enabled
        if (!$this->automaticTagsEnabled()) {
            return;
        }

        // log the start of the job
        $this->publication->addLog("Automatic tags module started.", self::SLUG_NAME);

        try {

            // get the openai preset
            $preset = Preset::findFromAPI("generate_tags");

            // run the preset
            $response = $preset->process([
                "language" => $this->getLanguage()->value,
                "request" => $this->getTitle(),
            ]);

            // get the response content
            $response = json_decode(Arr::get($response, 'choices.0.message.content'), true, 512, JSON_THROW_ON_ERROR);
            $items = Arr::get($response, "values");

            if (!empty($items)) {

                // clean tags
                $items = array_map(function ($str) {
                    return Str::clean($str);
                }, $items);
                $items = array_slice($items, 0, 5);
                $items = array_map([Str::class, 'lower'], $items);

                // add tags to the generation state
                $this->generationState->setArtifact("tags", $items);

                $this->publication->addLog("Automatic tags module completed successfully.", self::SLUG_NAME, "success");
            } else {
                $this->publication->addLog("Automatic tags module failed. No tags generated.", self::SLUG_NAME, "warning");
            }
        } catch (Exception $e) {
            $this->publication->addLog("Automatic tags module failed. " . $e->getMessage(), self::SLUG_NAME, "warning");
        }
    }

    /**
     * Generate automatic category
     *
     * @return void
     */
    private function handleAutomaticCategory(): void
    {
        // verify that the automatic tags are enabled
        if (!$this->automaticCategoryEnabled()) {
            return;
        }

        // log the start of the job
        $this->publication->addLog("Automatic category module started.", self::SLUG_NAME);

        try {

            // get categories
            $categories = array_map(function ($cat) {
                return ["id" => $cat->term_id, "name" => $cat->name];
            }, get_categories(['hide_empty' => 0]));

            // get the openai preset
            $preset = Preset::findFromAPI("get_best_category");

            // run the preset
            $response = $preset->process([
                "language" => $this->getLanguage()->value,
                "categories" => json_encode($categories),
                "request" => $this->getTitle(),
            ]);

            // get the response content
            $response = json_decode(Arr::get($response, 'choices.0.message.content'), true, 512, JSON_THROW_ON_ERROR);
            $category = Arr::get($response, "category");
            if (is_array($category)) {
                $category = Arr::first($category);
            }

            $categories = Arr::keyBy($categories, 'id');
            if (!empty($category) && isset($categories[$category])) {
                // add category to the generation state
                $this->generationState->setArtifact("category", $category);

                $this->publication->addLog("Automatic category module completed successfully.", self::SLUG_NAME, "success");
            } else {
                $this->publication->addLog("Automatic category module failed. No category found.", self::SLUG_NAME, "warning");
            }
        } catch (Exception $e) {
            $this->publication->addLog("Automatic category module failed. " . $e->getMessage(), self::SLUG_NAME, "warning");
        }
    }

    /**
     * Generate a SEO title
     *
     * @return void
     */
    private function handleSeoTitle(): void
    {
        // verify that the seo title generation is enabled
        if (!$this->seoTitleEnabled()) {
            return;
        }

        // log the start of the job
        $this->publication->addLog("SEO title module started.", self::SLUG_NAME);

        try {

            // get the openai preset
            $preset = Preset::findFromAPI('generate_seo_title');

            // run the preset
            $response = $preset->process([
                "language" => $this->getLanguage()->value,
                "request" => $this->getTitle(),
                "has_emojis" => $this->getModuleValue("wordpress.seo_title.emojis.enabled", false),
            ]);

            // get the response content
            $response = json_decode(Arr::get($response, 'choices.0.message.content'), true, 512, JSON_THROW_ON_ERROR);
            $content = Arr::get($response, "value");
            $content = Str::clean($content);

            if (!empty($content)) {

                // clean content
                $content = Str::clean($content);

                // add title to the generation state
                $this->generationState->setArtifact("seo_title", $content);

                $this->publication->addLog("SEO title module completed successfully.", self::SLUG_NAME, "success");
            } else {
                $this->publication->addLog("SEO title module failed. No title generated.", self::SLUG_NAME, "warning");
            }
        } catch (Exception $e) {
            $this->publication->addLog("SEO title module failed. " . $e->getMessage(), self::SLUG_NAME, "warning");
        }
    }

    /**
     * Generate a SEO description
     *
     * @return void
     */
    private function handleSeoDescription(): void
    {
        // verify that the seo description generation is enabled
        if (!$this->seoDescriptionEnabled()) {
            return;
        }

        // log the start of the job
        $this->publication->addLog("SEO description module started.", self::SLUG_NAME);

        try {

            // get the openai preset
            $preset = Preset::findFromAPI('generate_seo_description');

            // run the preset
            $response = $preset->process([
                "language" => $this->getLanguage()->value,
                "request" => $this->getTitle(),
            ]);

            // get the response content
            $response = json_decode(Arr::get($response, 'choices.0.message.content'), true, 512, JSON_THROW_ON_ERROR);
            $content = Arr::get($response, "value");
            $content = Str::clean($content);

            if (!empty($content)) {

                // add description to the generation state
                $this->generationState->setArtifact("seo_description", $content);

                $this->publication->addLog("SEO description module completed successfully.", self::SLUG_NAME, "success");
            } else {
                $this->publication->addLog("SEO description module failed. No description generated.", self::SLUG_NAME, "warning");
            }
        } catch (Exception $e) {
            $this->publication->addLog("SEO description module failed. " . $e->getMessage(), self::SLUG_NAME, "warning");
        }
    }

    /**
     * Determine if the automatic tags module is runnable
     *
     * @return boolean
     */
    private function automaticTagsEnabled(): bool
    {
        // must be enabled
        if (!$this->getModuleValue("wordpress.tags.automatic.enabled", false)) {
            return false;
        }

        return true;
    }

    /**
     * Determine if the automatic category module is runnable
     *
     * @return boolean
     */
    private function automaticCategoryEnabled(): bool
    {
        // must be enabled
        if (!$this->getModuleValue("wordpress.categories.automatic.enabled", false)) {
            return false;
        }

        return true;
    }

    /**
     * Determine if the SEO title module is runnable
     *
     * @return boolean
     */
    private function seoTitleEnabled(): bool
    {
        // must be enabled
        if (!$this->getModuleValue("wordpress.seo_title.enabled", false)) {
            return false;
        }

        return true;
    }

    /**
     * Determine if the SEO description module is runnable
     *
     * @return boolean
     */
    private function seoDescriptionEnabled(): bool
    {
        // must be enabled
        if (!$this->getModuleValue("wordpress.seo_description.enabled", false)) {
            return false;
        }

        return true;
    }

    /**
     * Determine if the module is runnable
     *
     * @return boolean
     */
    public function isRunnable(): bool
    {
        return $this->getType() !== "regenerate" && ($this->automaticTagsEnabled() || $this->automaticCategoryEnabled() || $this->seoTitleEnabled() || $this->seoDescriptionEnabled());
    }

    static public function isEnabled(Publishable $publishable): bool
    {
        return true;
    }
}
