<?php

namespace OtomaticAi\Controllers\SingleMode;

use Exception;
use OtomaticAi\Content\Image\Image;
use OtomaticAi\Controllers\Controller;
use OtomaticAi\Models\Presets\Preset;
use OtomaticAi\Models\SingleModeGeneration;
use OtomaticAi\Models\WP\Post;
use OtomaticAi\Utils\Language;
use OtomaticAi\Vendors\Carbon\Carbon;
use OtomaticAi\Vendors\Illuminate\Support\Arr;
use OtomaticAi\Vendors\Illuminate\Support\Str;

class PublishController extends Controller
{
    public function __invoke()
    {
        $this->verifyNonce();

        $this->validate([
            "id" => ["required", "integer"],
            "publish_date" => ["nullable", "date"],
            "post_type" => ["required", "string"],
            "author_id" => ["nullable"],
            "parent_page_id" => ["nullable"],
            "categories.automatic.enabled" => ["boolean"],
            "categories.custom" => ["nullable", "array"],
            "tags.automatic.enabled" => ["boolean"],
            "tags.custom" => ["nullable", "array"],
            "template" => ["nullable", "string"],
            "status" => ["required", "string"],
            "rewrite_permalink.enabled" => ["boolean"],
        ]);

        $model = SingleModeGeneration::find($this->input("id"));

        if ($model === null) {
            $this->response(["message" => "An error occurred", "error" => "Unable to find the generation #" . $this->input("id") . "."], 503);
        }

        $post = $model->post;
        if (!$post) {
            $post = new Post;

            // rewrite permalink if enabled
            if ($this->input('rewrite_permalink.enabled', false)) {
                try {
                    $preset = Preset::findFromAPI("rewrite_title_shorter");
                    $response = $preset->process(["title" => $model->title, "language" => $model->language->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 = $model->title;
        $post->post_status = $this->input("status", "publish");
        $post->post_content = $model->toWordpress();
        $post->post_type = $this->input("post_type", "post");

        if ($this->input("publish_date") !== null) {
            $publishDate = new Carbon($this->input("publish_date"));
            $post->post_date_gmt = $publishDate->format("Y-m-d H:i:s");
        }

        // author id
        $persona = $model->persona;
        if (!empty($persona)) {
            $post->post_author = $persona->user->ID;
        } else if (!empty($this->input("author_id"))) {
            $post->post_author = $this->input("author_id");
        }

        // post_parent with parent page id
        if ($this->input("parent_page_id") !== null && $this->input("post_type", "post") === 'page') {
            $parentPost = Post::find($this->input("parent_page_id"));
            if (!empty($parentPost)) {
                $post->post_parent = $parentPost->ID;
            }
        }

        $post->save();

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

        // thumbnail
        if (($image = Arr::get($model->extras, "thumbnail")) !== null) {
            $image = Image::fromArray($image);
            if ($image !== null) {
                if (($attachmentId = $image->image->save($model->title, $image->description, $image->legend)) !== null) {
                    set_post_thumbnail($post->ID, $attachmentId);
                }
            }
        }

        // page template
        if (!empty($this->input("template"))) {
            update_post_meta($post->ID, "_wp_page_template", $this->input("template"));
        }

        // categories
        $categories = [];
        if ($this->input("categories.automatic.enabled", false)) {
            $automaticCategory = $this->generateAutomaticCategory($model->title, $model->language);
            if ($automaticCategory !== null) {
                $categories[] = $automaticCategory;
            }
        } else if (!empty($this->input("categories.custom", []))) {
            $categories = array_merge($categories, $this->input("categories.custom", []));
        }
        if (count($categories) > 0) {
            wp_set_post_categories($post->ID, $categories);
        }

        // tags
        $tags = [];
        if ($this->input("tags.automatic.enabled", false)) {
            $automaticTags = $this->generateAutomaticTags($model->title, $model->language);
            if ($automaticTags !== null) {
                $tags = array_merge($tags, $automaticTags);
            }
        }
        if (!empty($this->input("tags.custom", []))) {
            $tags = array_merge($tags, $this->input("tags.custom", []));
        }
        if (count($tags) > 0) {
            wp_set_post_tags($post->ID, $tags);
        }

        // SEO title
        $seoTitle = Arr::get($model->settings, "seo_title");
        if (!empty($seoTitle)) {
            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
        $seoDescription = Arr::get($model->settings, "seo_description");
        if (!empty($seoDescription)) {
            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
        $customFields = Arr::get($model->extras, "custom_fields", []);
        foreach ($customFields as $customField) {
            $key = Arr::get($customField, "key");
            $value = Arr::get($customField, "value");
            if (!empty($key)) {
                update_post_meta($post->ID, $key, $value);
            }
        }

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

        $this->response($model->fresh());
    }

    /**
     * Generate the automatic category
     *
     * @param string $title
     * @param Language $language
     * @return string|null
     */
    private function generateAutomaticCategory(string $title, Language $language)
    {
        try {
            // get categories
            $categories = array_map(function ($cat) {
                return ["id" => $cat->term_id, "name" => $cat->name];
            }, get_categories(['hide_empty' => 0]));
            $categories = Arr::keyBy($categories, 'name');

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

            // run the preset
            $response = $preset->process([
                "language" => $language->value,
                "categories" => implode(", ", Arr::pluck($categories, "name")),
                "request" => $title,
            ]);

            // 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);
            }

            if (isset($categories[$category])) {
                return $categories[$category]["id"];
            }
        } catch (Exception $e) {
        }

        return null;
    }

    /**
     * Generate automatic tags
     *
     * @param string $title
     * @param Language $language
     * @return array
     */
    private function generateAutomaticTags(string $title, Language $language)
    {

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

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

            // 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);

                return $items;
            }
        } catch (Exception $e) {
        }

        return [];
    }
}
