<?php

namespace OtomaticAi\RestControllers;

use Exception;
use OtomaticAi\Models\Presets\Preset;
use OtomaticAi\Models\WP\Post;
use OtomaticAi\Utils\Gutemberg;
use OtomaticAi\Utils\Image;
use OtomaticAi\Utils\Language;
use OtomaticAi\Vendors\Carbon\Carbon;
use OtomaticAi\Vendors\Illuminate\Support\Arr;
use OtomaticAi\Vendors\Illuminate\Support\Str;
use WP_Error;
use WP_Query;

class WordpressRestController extends RestController
{
    public function users()
    {
        return get_users();
    }

    public function postTypes()
    {
        $postTypes = get_post_types([
            "public" => true,
        ], "object");

        $postTypes = array_filter($postTypes, function ($type) {
            return !in_array($type->name, ["attachment"]);
        });

        $postTypes = array_map(function ($type) {
            return [
                "name" => $type->name,
                "label" => $type->labels->singular_name
            ];
        }, $postTypes);

        $postTypes = array_values($postTypes);

        return $postTypes;
    }

    public function templates()
    {
        include_once ABSPATH . 'wp-admin/includes/theme.php';

        return get_page_templates();
    }

    public function categories()
    {
        return get_categories(['hide_empty' => 0]);
    }

    public function statuses()
    {
        return get_post_statuses();
    }

    public function userRoles()
    {
        require_once ABSPATH . 'wp-admin/includes/user.php';

        $roles = get_editable_roles();
        $roles = array_map(function ($role) {
            return $role["name"];
        }, $roles);

        return $roles;
    }

    public function relatedPosts()
    {
        $this->validate([
            "search" => "required|string",
        ]);

        $search = Str::lower($this->input("search"));
        if (empty($search)) {
            return [];
        }

        $args = [
            "s" => $search,
        ];

        // if the pll is installed, get only the posts in the default language
        if (function_exists("pll_the_languages") && function_exists("pll_default_language")) {
            $defaultLanguage = pll_default_language();
            $languages = pll_the_languages(['raw' => 1]);

            if (isset($languages[$defaultLanguage], $languages[$defaultLanguage]["id"])) {
                $args['tax_query'] = [
                    [
                        'taxonomy' => 'language',
                        'field' => 'term_id',
                        'terms' => $languages[$defaultLanguage]["id"]
                    ]
                ];
            }
        }

        $query = new WP_Query($args);

        $relatedPosts = $query->get_posts();
        if (!empty($relatedPosts)) {
            $relatedPosts = array_map(function ($post) {
                return [
                    "id" => $post->ID,
                    "content" => get_the_title($post),
                    "link" => get_permalink($post),
                ];
            }, $relatedPosts);

            return $relatedPosts;
        }


        return [];
    }

    public function publishPost()
    {
        $this->validate([
            "title" => ["required", "string"],
            "language_code" => ["required", "string"],
            "thumbnail" => ["nullable", "array"],
            "content" => ["required", "string"],
            "post_id" => ["nullable"],
            "settings.author_id" => ["nullable"],
            "settings.publish_date" => ["nullable", "date"],
            "settings.post_type" => ["required", "string"],
            "settings.categories.automatic.enabled" => ["boolean"],
            "settings.categories.custom" => ["nullable", "array"],
            "settings.tags.automatic.enabled" => ["boolean"],
            "settings.tags.custom" => ["nullable", "array"],
            "settings.template" => ["nullable", "string"],
            "settings.status" => ["required", "string"],
            "settings.rewrite_permalink.enabled" => ["boolean"],
            "settings.rewrite_permalink.value" => ["nullable", "string"],
            "settings.seo_title" => ["nullable", "string"],
            "settings.seo_description" => ["nullable", "string"],

        ]);

        require_once(ABSPATH . "wp-admin" . '/includes/image.php');
        require_once(ABSPATH . "wp-admin" . '/includes/file.php');
        require_once(ABSPATH . "wp-admin" . '/includes/media.php');

        // set the current user
        if (!empty($this->input("settings.author_id"))) {
            wp_set_current_user($this->input("settings.author_id"));
        } else if (!empty($first = Arr::get(get_users(["fields" => 'ID']), 0))) {
            wp_set_current_user($first);
        }

        $language = Language::find($this->input("language_code"), "fr");

        $post = new Post;
        if ($this->input("post_id") !== null) {
            $model = Post::find($this->input("post_id"));

            if ($model) {
                $post = $model;
            }
        }

        // rewrite permalink if enabled
        if ($this->input("settings.rewrite_permalink.enabled", false)) {
            $permalink = $this->input("settings.rewrite_permalink.value");
            $permalink = Str::clean($permalink);
            if (!empty($permalink)) {
                $post->post_name = $permalink;
            }
        }

        $post->post_title = $this->input("title");
        $post->post_status = $this->input("settings.status", "publish");
        $post->post_type = $this->input("settings.post_type", "post");

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

        // author id
        if ($this->input("settings.author_id") !== null) {
            $post->post_author = $this->input("settings.author_id");
        }

        $content = $this->input("content");
        $content = wp_encode_emoji($content);
        $converter = new Gutemberg([
            "auto_p" => false,
            "title" => $this->input("title")
        ]);
        $content = $converter->convert_blocks($content);
        $post->post_content = $content;

        $post->save();

        if ($post->ID === null) {
            return new WP_Error('error', 'Unable to create the post.', ['status' => 503]);
        }

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

        // thumbnail
        if ($this->input("thumbnail") !== null) {
            $thumbnailUrl = $this->input("thumbnail.url");
            $thumbnailAlt = $this->input("thumbnail.alt");

            if (!empty($thumbnailUrl)) {
                $image = Image::fromUrl($thumbnailUrl);
                if ($image !== null) {
                    if (($attachmentId = $image->save($this->input("title"), $thumbnailAlt)) !== null) {
                        set_post_thumbnail($post->ID, $attachmentId);
                    }
                }
            }
        }

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

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

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

        // SEO title
        $seoTitle = $this->input("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 = $this->input("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);
        }

        return [
            "id" => $post->ID,
            "title" => $post->post_title,
            "display_link" => get_permalink($post->ID),
            "edit_link" => get_edit_post_link($post->ID, 'json'),
        ];
    }

    /**
     * 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 [];
    }
}
