<?php

namespace OtomaticAi\Controllers;

use Exception;
use OtomaticAi\Models\Persona;
use OtomaticAi\Models\Presets\Preset;
use OtomaticAi\Models\Project;
use OtomaticAi\Models\Publication;
use OtomaticAi\Utils\Planning;
use OtomaticAi\Utils\RSS\Reader;
use OtomaticAi\Vendors\Carbon\Carbon;
use OtomaticAi\Vendors\Illuminate\Support\Arr;
use OtomaticAi\Vendors\Illuminate\Support\Collection;
use OtomaticAi\Vendors\Illuminate\Validation\Rule;

class ProjectController extends Controller
{
    public function index()
    {
        $this->verifyNonce();

        $this->validate([
            "page" => ["nullable", "integer"],
            "sort_order" => ["nullable", "string"],
            "sort_direction" => ["nullable", "string", Rule::in(["asc", "desc"])],
            "search" => ["nullable", "string"],
        ]);

        $projects = $this->makeQuery();
        $projects->with(["persona"]);
        $projects = $projects->paginate(15, ['*'], 'page', $this->input('page', 1))->onEachSide(1);

        $this->response($projects);
    }

    public function latest()
    {
        $this->verifyNonce();

        $this->validate([
            "limit" => ["nullable", "integer", "min:1"],
        ]);

        $projects = Project::latest()
            ->limit($this->input("limit", 5))
            ->with("firstPublishedPublication")
            ->get();

        $this->response($projects);
    }

    public function show()
    {
        $this->verifyNonce();

        $this->validate([
            "id" => ["required"],
        ]);

        $project = Project::find($this->input("id"));

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

        $this->response($project);
    }

    public function store()
    {
        $this->verifyNonce();

        $this->validateName();
        $this->validateLanguage();
        $this->validatePersona();
        $this->validateType();
        $this->validateRequests();
        $this->validatePlanning();

        $validatedModules = $this->validateModules();

        // create the project
        $modules = Arr::get($validatedModules, "modules", []);
        $modules["_version"] = Project::$version;
        $project = new Project([
            "name" => $this->input("name", "new project"),
            "language" => $this->input("language"),
            "type" => $this->input("type"),
            "enabled" => true,
            "modules" => $modules,
            "planning" => $this->input("planning", []),
        ]);

        if (!empty($this->input("persona_id"))) {
            $persona = Persona::find($this->input("persona_id"));
            if ($persona) {
                $project->persona()->associate($persona);
            }
        }
        $project->save();

        // create publications and store
        $requests = $this->input("requests", []);

        // flatten requests
        $requests = $this->flattenRequests($requests);

        if (count($requests) > 0) {
            if (!$this->input("planning.enabled", false)) {

                foreach ($requests as $key => $request) {
                    $key = strval($request["key"]);
                    $parentKey = isset($request["parent_key"]) ? strval($request["parent_key"]) : '';

                    // create a new publication
                    $publication = new Publication([
                        "title" => $request["title"],
                        "meta" => Arr::get($request, "meta", []),
                        "published_at" => Carbon::now(),
                    ]);

                    // attache the project to publication
                    $publication->project()->associate($project);

                    // get the parent publication and attach it if exist
                    $parentPublication = Arr::get($requests, $parentKey . ".publication");
                    if (!empty($parentPublication)) {
                        $publication->parent_id = $parentPublication;
                    }

                    // add the post_id to the publication if exist
                    if (!empty(Arr::get($request, "meta.post_id"))) {
                        $publication->post_id = Arr::get($request, "meta.post_id");
                    }

                    // save the publication
                    $publication->saveQuietly();
                    $requests[$key]["publication"] = $publication->id;
                }
            } else {
                $planning = new Planning($requests);
                $planning
                    ->perPeriod($this->input("planning.per_period", 1))
                    ->period($this->input("planning.period", "day"))
                    ->startDate(Carbon::createFromFormat("Y-m-d", $this->input("planning.start_date", Carbon::now()->format("Y-m-d"))))
                    ->startTime($this->input("planning.start_time.hours", 6),  $this->input("planning.start_time.minutes", 30))
                    ->endTime($this->input("planning.end_time.hours", 21),  $this->input("planning.end_time.minutes", 0))
                    ->weekdays($this->input("planning.days", [Planning::MONDAY, Planning::THURSDAY, Planning::WEDNESDAY, Planning::THURSDAY, Planning::FRIDAY]))
                    ->each(function ($request, $date) use ($project, &$requests) {

                        // create a new publication
                        $publication = new Publication([
                            "title" => $request["title"],
                            "meta" => Arr::get($request, "meta", []),
                            "published_at" => $date,
                        ]);

                        // attache the project to publication
                        $publication->project()->associate($project);

                        // get the parent publication and attach it if exist
                        $parentPublication = Arr::get($requests, Arr::get($request, "parent_key") . ".publication");
                        if (!empty($parentPublication)) {
                            $publication->parent_id = $parentPublication;
                        }

                        // add the post_id to the publication if exist
                        if (!empty(Arr::get($request, "meta.post_id"))) {
                            $publication->post_id = Arr::get($request, "meta.post_id");
                        }

                        // save the publication
                        $publication->saveQuietly();
                        $requests[$request["key"]]["publication"] = $publication->id;
                    });
            }

            $project->refreshMetrics();
        }

        $this->response($project);
    }

    public function update()
    {
        $this->verifyNonce();
        $this->validate([
            "id" => ["required"],
        ]);
        $this->validateName();
        $this->validateLanguage();
        $this->validatePersona();

        $validatedModules = $this->validateModules();

        // get the project
        $project = Project::find($this->input("id"));
        $project->name = $this->input("name");
        $project->language = $this->input("language");

        if (!empty($this->input("persona_id")) && !empty($persona = Persona::find($this->input("persona_id")))) {
            $project->persona()->associate($persona);
        } else {
            $project->persona()->dissociate();
        }

        $modules = Arr::get($validatedModules, "modules", []);
        $modules["_version"] = Project::$version;
        $project->modules = $modules;

        if ($project->save()) {
            $this->emptyResponse();
        } else {
            $this->response(["message" => "An error occurred", "error" => "Unable to update the project."], 503);
        }
    }

    private function flattenRequests($requests, $parentKey = null)
    {
        $output = [];
        for ($i = 0; $i < count($requests); $i++) {
            $copy = $requests[$i];
            unset($copy["children"]);
            $localKey = $parentKey !== null ? $parentKey . '-' . ($i + 1) : ($i + 1);
            $copy["key"] = $localKey;
            if ($parentKey !== null) {
                $copy["parent_key"] = $parentKey;
            }

            $output[] = $copy;
            if (!empty($requests[$i]["children"])) {
                $output = array_merge($output, $this->flattenRequests($requests[$i]["children"], $localKey));
            }
        }

        return (new Collection($output))->keyBy('key')->toArray();
    }

    public function validateRequestsKeywordStep()
    {
        $this->verifyNonce();

        if ($this->input("type") === "rss" || $this->input("type") === "rss-now") {
            $feed = $this->input("modules.autopilot.query");

            if (!empty($feed)) {
                try {
                    Reader::load($feed);
                    $this->emptyResponse();
                } catch (Exception $e) {
                }
            }

            $this->response(["message" => "Unable to load feed.", "errors" => ['modules.autopilot.query' => ["Unable to load feed."]]], 422);
        }

        $this->emptyResponse();
    }

    public function validateRequestsStep()
    {
        $this->verifyNonce();

        $this->validateRequests();

        $this->emptyResponse();
    }

    public function validateContentStep()
    {
        $this->verifyNonce();

        $this->validatePersona();
        $this->validateModules();

        $this->emptyResponse();
    }

    public function validatePlanningStep()
    {
        $this->verifyNonce();

        $this->validatePlanning();

        $this->emptyResponse();
    }

    public function rewriteCustomInstructions()
    {
        $this->verifyNonce();

        $this->validate([
            "prompt" => ["required", "string"],
        ]);

        $preset = Preset::findFromAPI("automatic_template_rewrite_custom_instructions");

        $response = $preset->process([
            "user_prompt" => $this->input("prompt"),
        ]);

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

        $this->response([
            "original_prompt" => $this->input("prompt"),
            "rewritten_prompt" => Arr::get($response, "rewritten_prompt", $this->input("prompt")),
        ]);
    }

    public function enable()
    {
        $this->verifyNonce();

        $this->validate([
            "project" => ["required", "integer"],
        ]);

        $project = Project::find($this->input('project'));
        if ($project) {
            $project->enabled = true;
            $project->save();
        }

        $this->emptyResponse();
    }

    public function disable()
    {
        $this->verifyNonce();

        $this->validate([
            "project" => ["required", "integer"],
        ]);

        $project = Project::find($this->input('project'));
        if ($project) {
            $project->enabled = false;
            $project->save();
        }

        $this->emptyResponse();
    }

    public function destroy()
    {
        $this->verifyNonce();

        $this->validate([
            "project" => ["required", "integer"],
        ]);

        $project = Project::find($this->input('project'));
        if ($project) {
            $project->publications()->delete();
            $project->delete();
        }

        $this->emptyResponse();
    }

    private function makeQuery()
    {
        $projects = Project::query();

        // sort 
        if (!empty($sortOrder = $this->input('sort_order', ''))) {
            $projects->orderBy($sortOrder, $this->input('sort_direction', 'desc'));
        } else {
            $projects->orderBy("id", "desc");
        }

        if (!empty($type = $this->input('type', ''))) {
            $projects->where("type", $type);
        }
        if (($enabled = $this->input('enabled', null)) !== null) {
            $projects->where("enabled", $enabled);
        }

        return $projects;
    }

    // validators
    private function validateName()
    {
        return $this->validate([
            "name" => ["required", "string"],
        ]);
    }

    private function validateLanguage()
    {
        return $this->validate([
            "language" => ["required", "string"],
        ]);
    }

    private function validatePersona()
    {
        return $this->validate([
            "persona_id" => ["nullable"],
        ]);
    }

    private function validateType()
    {
        return $this->validate([
            "type" => ["required"],
        ]);
    }

    private function validateRequests()
    {
        return $this->validate([
            "requests" => ["required_unless:type,rss,news", "array"],
        ]);
    }

    private function validateModules()
    {
        $rules = array_merge_recursive(
            $this->getModelsModuleRules(),
            $this->getContentModuleRules(),
            $this->getWordpressModuleRules(),
            $this->getAutopilotModuleRules(),
        );

        return $this->validate($rules["rules"], [], $rules["custom_attributes"]);
    }

    private function validatePlanning()
    {
        $this->validate([
            "planning.enabled" => ["boolean"],
            "planning.start_date" => ["date"],
            "planning.per_period" => ["integer", "min:1"],
            "planning.period" => ["string", "required"],
            "planning.days.monday" => ["boolean"],
            "planning.days.tuesday" => ["boolean"],
            "planning.days.wednesday" => ["boolean"],
            "planning.days.thursday" => ["boolean"],
            "planning.days.friday" => ["boolean"],
            "planning.days.saturday" => ["boolean"],
            "planning.days.sunday" => ["boolean"],
            "planning.start_time.hours" => ["integer", "min:0", "max:23"],
            "planning.start_time.minutes" => ["integer", "min:0", "max:59"],
            "planning.end_time.hours" => ["integer", "min:0", "max:23"],
            "planning.end_time.minutes" => ["integer", "min:0", "max:59"],
        ]);
    }

    // validation rules
    private function getModelsModuleRules()
    {
        return [
            "rules" => [
                "modules.models.text" => ["required", "string"],
                "modules.models.image" => ["required", "string"],
            ],
            "custom_attributes" => [
                "modules.models.text" => "text model",
                "modules.models.image" => "image model",
            ]
        ];
    }

    private function getContentModuleRules()
    {
        return [
            "rules" => [
                "modules.content.writing_style" => ["nullable", "string"],
                "modules.content.sources.enabled" => ["boolean"],
                "modules.content.sources.no_follow" => ["boolean"],
                "modules.content.sources.blank" => ["boolean"],
                "modules.content.custom_instructions.profile" => ["nullable", "string"],
                "modules.content.custom_instructions.images" => ["nullable", "string"],
                "modules.content.custom_instructions.text" => ["nullable", "string"],
                "modules.content.blocks" => ["nullable", "array"],
                "modules.content.automatic.enabled" => ["boolean"],
                "modules.content.automatic.text_length" => ["required", "string"],
                "modules.content.automatic.images.enabled" => ["boolean"],
                "modules.content.automatic.images.max_images" => ["integer", "min:0"],
                "modules.content.automatic.youtube.enabled" => ["boolean"],
                "modules.content.automatic.embeds.enabled" => ["boolean"],
                "modules.content.automatic.internal_links.enabled" => ["boolean"],
                "modules.content.automatic.internal_links.no_follow" => ["boolean"],
                "modules.content.automatic.external_links.enabled" => ["boolean"],
                "modules.content.automatic.external_links.no_follow" => ["boolean"],
                "modules.content.automatic.custom_links.enabled" => ["boolean"],
                "modules.content.automatic.custom_links.links" => ["nullable", "array"],
                "modules.content.automatic.lists.enabled" => ["boolean"],
                "modules.content.automatic.tables.enabled" => ["boolean"],
                "modules.content.automatic.bold_words.enabled" => ["boolean"],
                "modules.content.automatic.emojis.enabled" => ["boolean"],
                "modules.content.automatic.summary.enabled" => ["boolean"],
                "modules.content.automatic.brief.enabled" => ["boolean"],
                "modules.content.automatic.faq.enabled" => ["boolean"],
                "modules.content.automatic.toolbox.enabled" => ["boolean"],
                "modules.content.automatic.toolbox.template" => ["nullable", "string"],
                "modules.content.automatic.keywords.automatic.enabled" => ["boolean"],
                "modules.content.automatic.keywords.custom" => ["nullable", "array"],
                "modules.content.automatic.amazon.enabled" => ["boolean"],
                "modules.content.automatic.amazon.template" => ["nullable", "string"],
                "modules.content.automatic.amazon.max_products" => ["integer", "min:0"],
            ],
            "custom_attributes" => [
                "modules.content.writing_style" => "writing style",
                "modules.content.sources.enabled" => "sources",
                "modules.content.sources.no_follow" => "no follow",
                "modules.content.sources.blank" => "blank",
                "modules.content.custom_instructions.profile" => "profile",
                "modules.content.custom_instructions.images" => "images",
                "modules.content.custom_instructions.text" => "text",
                "modules.content.blocks" => "blocks",
                "modules.content.automatic.enabled" => "automatic",
                "modules.content.automatic.settings.text_length" => "text length",
                "modules.content.automatic.settings.images.enabled" => "images",
                "modules.content.automatic.settings.images.max_images" => "max images",
                "modules.content.automatic.settings.youtube.enabled" => "youtube",
                "modules.content.automatic.settings.embeds.enabled" => "embeds",
                "modules.content.automatic.settings.internal_links.enabled" => "internal links",
                "modules.content.automatic.settings.internal_links.no_follow" => "internal links no follow",
                "modules.content.automatic.settings.external_links.enabled" => "external links",
                "modules.content.automatic.settings.external_links.no_follow" => "external links no follow",
                "modules.content.automatic.settings.custom_links.enabled" => "custom links",
                "modules.content.automatic.settings.custom_links.links" => "links",
                "modules.content.automatic.settings.lists.enabled" => "lists",
                "modules.content.automatic.settings.tables.enabled" => "tables",
                "modules.content.automatic.settings.bold_words.enabled" => "bold words",
                "modules.content.automatic.settings.emojis.enabled" => "emojis",
                "modules.content.automatic.settings.summary.enabled" => "summary",
                "modules.content.automatic.settings.brief.enabled" => "brief",
                "modules.content.automatic.settings.faq.enabled" => "faq",
                "modules.content.automatic.settings.toolbox.enabled" => "toolbox",
                "modules.content.automatic.settings.toolbox.template" => "toolbox template",
                "modules.content.automatic.settings.keywords.automatic.enabled" => "automatic keywords",
                "modules.content.automatic.settings.keywords.custom" => "custom keywords",
                "modules.content.automatic.settings.amazon.enabled" => "amazon",
                "modules.content.automatic.settings.amazon.template" => "amazon template",
                "modules.content.automatic.settings.amazon.max_products" => "max products",
            ]
        ];
    }

    private function getWordpressModuleRules()
    {
        return [
            "rules" => [
                "modules.wordpress.thumbnail.enabled" => ["boolean"],
                "modules.wordpress.post_type" => ["required", "string"],
                "modules.wordpress.author_id" => ["nullable"],
                "modules.wordpress.template" => ["nullable", "string"],
                "modules.wordpress.parent_page_id" => ["nullable"],
                "modules.wordpress.categories.automatic.enabled" => ["boolean"],
                "modules.wordpress.categories.custom" => ["array"],
                "modules.wordpress.tags.automatic.enabled" => ["boolean"],
                "modules.wordpress.tags.custom" => ["array"],
                "modules.wordpress.status" => ["string", "required"],
                "modules.wordpress.seo_title.enabled" => ["boolean"],
                "modules.wordpress.seo_title.emojis.enabled" => ["boolean"],
                "modules.wordpress.seo_description.enabled" => ["boolean"],
                "modules.wordpress.custom_fields" => ["array"],
                "modules.wordpress.rewrite_permalink.enabled" => ["boolean"],
            ],
            "custom_attributes" => [
                "modules.wordpress.thumbnail.enabled" => "thumbnail",
                "modules.wordpress.post_type" => "post type",
                "modules.wordpress.author_id" => "author",
                "modules.wordpress.template" => "page template",
                "modules.wordpress.parent_page_id" => "parent page ID",
                "modules.wordpress.categories.automatic.enabled" => "automatic category",
                "modules.wordpress.categories.custom" => "categories",
                "modules.wordpress.tags.automatic.enabled" => "automatic tags",
                "modules.wordpress.tags.custom" => "tags",
                "modules.wordpress.status" => "post status",
                "modules.wordpress.seo_title.enabled" => "SEO title",
                "modules.wordpress.seo_title.emojis.enabled" => "emojis",
                "modules.wordpress.seo_description.enabled" => "SEO description",
                "modules.wordpress.custom_fields" => "custom fields",
                "modules.wordpress.rewrite_permalink.enabled" => "rewrite permalink",
            ]
        ];
    }

    private function getAutopilotModuleRules()
    {
        return [
            "rules" => [
                "modules.autopilot.query" => ["nullable", "string"],
                "modules.autopilot.source_language" => ["nullable", "string"],
                "modules.autopilot.planning.per_day" => ["integer", "min:0"],
                "modules.autopilot.planning.start_time.hours" => ["integer", "min:0", "max:23"],
                "modules.autopilot.planning.start_time.minutes" => ["integer", "min:0", "max:59"],
                "modules.autopilot.planning.end_time.hours" => ["integer", "min:0", "max:23"],
                "modules.autopilot.planning.end_time.minutes" => ["integer", "min:0", "max:59"],
            ],
            "custom_attributes" => [
                "modules.autopilot.query" => 'query',
                "modules.autopilot.source_language" => 'source language',
                "modules.autopilot.planning.per_day" => 'number of posts per day',
            ]
        ];
    }
    // ----
}
