<?php

namespace OtomaticAi\Modules;

use DOMXPath;
use Exception;
use OtomaticAi\Api\OtomaticAi\Client;
use OtomaticAi\Content\Image\Image;
use OtomaticAi\Models\Contracts\Publishable;
use OtomaticAi\Modules\Contracts\Module as ModuleContract;
use OtomaticAi\Models\Presets\Preset;
use OtomaticAi\Models\WP\Post;
use OtomaticAi\Utils\Analytics;
use OtomaticAi\Vendors\Illuminate\Support\Arr;
use OtomaticAi\Vendors\Illuminate\Support\Str;
use OtomaticAi\Utils\Gutemberg;

class ProcessNetlinkingFinalizeModule extends Module implements ModuleContract
{
    const SLUG_NAME = "process_netlinking_finalize_module";

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

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

        // remove remaining placeholders
        $xpath = new DOMXPath($this->html);
        $nodes = $xpath->query("//placeholder");
        foreach ($nodes as $node) {
            $node->parentNode->removeChild($node);
        }

        // make content
        $content = trim(preg_replace("/^<body>|<\/body>$/", "", $this->html->saveHTML($this->html->getElementsByTagName("body")->item(0))));

        // encode emojis with wordpress
        $content = wp_encode_emoji($content);

        // convert blocks with gutemberg
        $converter = new Gutemberg();
        $content = $converter->convert_blocks($content);

        // quit if no content generated
        if (empty($content)) {
            throw new Exception("No content generated");
        }

        // create or update the post
        $post = $this->publication->post;
        if (!$post) {
            $post = new Post;

            // rewrite permalink if enabled
            if ($this->getModuleValue('wordpress.rewrite_permalink.enabled', false)) {
                try {
                    $preset = Preset::findFromAPI("rewrite_title_shorter");
                    $response = $preset->process(["title" => $this->publication->title, "language" => $this->getLanguage()->value]);
                    $response = json_decode(Arr::get($response, 'choices.0.message.content'), true, 512, JSON_THROW_ON_ERROR);
                    $permalink = Arr::get($response, "shortened_title");
                    $permalink = Str::clean($permalink);
                    if (!empty($permalink)) {
                        $post->post_name = $permalink;
                    }
                } catch (Exception $e) {
                }
            }
        }

        $post->post_title = $this->publication->title;
        $post->post_content = $content;

        // set post status
        if ($this->getType() !== "regenerate") {
            $post->post_status = $this->getModuleValue('wordpress.status');
        }

        // set post type
        if ($this->getType() === "siloing") {
            $post->post_type = "page";
        } else {
            $post->post_type = $this->getModuleValue('wordpress.post_type', 'post');
        }

        // set post author
        if ($this->getType() !== "regenerate" && !empty($this->getModuleValue('wordpress.author_id'))) {
            $post->post_author = $this->getModuleValue('wordpress.author_id');
        }

        // post_parent with publication parent
        if ($this->getType() !== "regenerate" && $this->getModuleValue('wordpress.post_type', 'post') === 'page') {
            $parent = $this->publication->parent;
            if ($parent && $parent->status === 'success') {
                $post->post_parent = $parent->post_id;
            } else {
                $parentPageId = $this->getModuleValue('wordpress.parent_page_id');
                if (!empty($parentPageId) && !empty(Post::find($parentPageId))) {
                    $post->post_parent = $parentPageId;
                }
            }
        }

        $post->save();

        // ---------------
        // extras details
        // ---------------

        // thumbnail
        if (($image = $this->generationState->getArtifact('thumbnail')) !== null) {
            $image = Image::fromArray($image);
            if ($image !== null) {
                if (($attachmentId = $image->image->save($this->publication->title, $image->description, $image->legend)) !== null) {
                    if (set_post_thumbnail($post->ID, $attachmentId) === false) {
                        $this->publication->addLog("Unable to save the post thumbnail.", self::SLUG_NAME, "warning");
                    }
                }
            }
        }

        // page template
        if ($this->getType() !== "regenerate" && !empty($this->getModuleValue('wordpress.template'))) {
            if (update_post_meta($post->ID, "_wp_page_template", $this->getModuleValue('wordpress.template')) === false) {
                $this->publication->addLog("Unable to save the page template.", self::SLUG_NAME, "warning");
            }
        }

        // attach categories
        if ($this->getType() !== "regenerate") {
            $categories = [];
            if (!empty($category = $this->generationState->getArtifact('category'))) {
                $categories[] = $category;
            } else if (!$this->getModuleValue('wordpress.categories.automatic.enabled', false) && count($this->getModuleValue('wordpress.categories.custom', [])) > 0) {
                $categories = $this->getModuleValue('wordpress.categories.custom', []);
            }
            if (count($categories) > 0) {
                $arr = wp_set_post_categories($post->ID, $categories);
                if (is_wp_error($arr)) {
                    $this->publication->addLog("Unable to attach the categories. " . $arr->get_error_message(), self::SLUG_NAME, "warning");
                } else if ($arr === false) {
                    $this->publication->addLog("Unable to attach the categories.", self::SLUG_NAME, "warning");
                }
            }
        }

        // add custom tags
        if ($this->getType() !== "regenerate") {
            $tags = [];
            if (count($this->getModuleValue('wordpress.tags.custom', [])) > 0) {
                $tags = array_merge($tags, $this->getModuleValue('wordpress.tags.custom', []));
            }

            // add automatic tags
            if (count($automaticTags = $this->generationState->getArtifact('tags', [])) > 0) {
                $tags = array_merge($tags, $automaticTags);
            }

            // attach tags
            if (count($tags) > 0) {
                $arr = wp_set_post_tags($post->ID, $tags);
                if (is_wp_error($arr)) {
                    $this->publication->addLog("Unable to attach the tags. " . $arr->get_error_message(), self::SLUG_NAME, "warning");
                } else if ($arr === false) {
                    $this->publication->addLog("Unable to attach the tags.", self::SLUG_NAME, "warning");
                }
            }
        }

        // SEO title
        if (($seoTitle = $this->generationState->getArtifact('seo_title', null)) !== null) {
            update_post_meta($post->ID, "_yoast_wpseo_title", $seoTitle);
            update_post_meta($post->ID, "rank_math_title", $seoTitle);
            update_post_meta($post->ID, "_seopress_titles_title", $seoTitle);
        }

        // SEO description
        if (($seoDescription = $this->generationState->getArtifact('seo_description', null)) !== null) {
            update_post_meta($post->ID, "_yoast_wpseo_metadesc", $seoDescription);
            update_post_meta($post->ID, "rank_math_description", $seoDescription);
            update_post_meta($post->ID, "_seopress_titles_desc", $seoDescription);
        }

        // custom fields
        foreach ($this->generationState->getArtifact('custom_fields', []) as $customField) {
            $key = Arr::get($customField, "key");
            $value = Arr::get($customField, "value");
            if (!empty($key)) {
                if (update_post_meta($post->ID, $key, $value) === false) {
                    $this->publication->addLog("Unable to save the custom field `" . $key . "`.", self::SLUG_NAME, "warning");
                }
            }
        }

        // attach the post to the publication
        $this->publication->post()->associate($post);

        // update the publication status to success
        $this->publication->status = "success";
        $this->publication->save();

        // track the end of the job
        Analytics::trackEvent("generate-netlinking-end", [
            "uuid" => $this->publication->uuid,
            "model" => $this->getModuleValue("models.text", 'gpt-4o-mini'),
            "image_model" => $this->getModuleValue("models.image", 'dall-e-3'),
        ]);

        // update the campaign status
        $api = new Client;
        $api->updateNetlinkingCampaign($this->publication->uuid, [
            "status" => "success",
            "url" => $this->publication->display_link
        ]);

        // track the end of the job
        Analytics::trackEvent("generate-netlinking-end", [
            "uuid" => $this->publication->uuid,
            "model" => $this->getModuleValue("models.text", 'gpt-4o-mini'),
            "image_model" => $this->getModuleValue("models.image", 'dall-e-3'),
        ]);

        // log the end of the job
        $this->publication->addLog("Finalize module completed successfully.", self::SLUG_NAME, "success");
    }

    /**
     * Determine if the module is runnable
     *
     * @return boolean
     */
    public function isRunnable(): bool
    {
        return true;
    }

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