<?php

namespace OtomaticAi\RestControllers;

use OtomaticAi\Models\Persona;
use OtomaticAi\Models\Project;
use OtomaticAi\Models\Publication;
use OtomaticAi\Utils\Planning;
use OtomaticAi\Vendors\Carbon\Carbon;
use OtomaticAi\Vendors\Illuminate\Support\Arr;
use OtomaticAi\Vendors\Illuminate\Support\Collection;
use WP_Error;

class ProjectRestController extends RestController
{
    public function index()
    {
        $this->validate([
            "page" => ["nullable", "integer"],
        ]);

        $projects = Project::orderBy("id", "desc")
            ->paginate(15, ['*'], 'page', $this->input('page', 1))
            ->onEachSide(1);

        $projects = $projects->toArray();

        // add meta to the response
        if (!isset($projects['meta'])) {
            $projects['meta'] = [
                "projects" => [
                    "total" => Project::count(),
                    "completed" => Project::completed()->count(),
                ],
                "publications" => [
                    "published" => Publication::published()->count(),
                    "idle" => Publication::idle()->count(),
                ],
            ];
        }

        return $projects;
    }

    public function show()
    {
        $id = $this->input('id');

        $project = Project::find($id);

        if (empty($project)) {
            return new WP_Error('not_found', 'Project not found', ['status' => 404]);
        }

        return $project;
    }

    public function store()
    {
        $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;
                    }

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

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

            $project->refreshMetrics();
        }

        return $project;
    }

    public function update()
    {
        $id = $this->input('id');

        $this->validateName();
        $this->validateLanguage();
        $this->validatePersona();

        $validatedModules = $this->validateModules();

        $project = Project::find($id);
        if (empty($project)) {
            return new WP_Error('not_found', 'Project not found', ['status' => 404]);
        }

        // update the project
        $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()) {
            return $project;
        }

        return new WP_Error('error', 'Unable to update the project.', ['status' => 503]);
    }

    public function enable()
    {
        $id = $this->input('id');

        $project = Project::find($id);

        if (empty($project)) {
            return new WP_Error('not_found', 'Project not found', ['status' => 404]);
        }

        $project->enabled = true;
        $project->save();

        return $project;
    }

    public function disable()
    {
        $id = $this->input('id');

        $project = Project::find($id);

        if (empty($project)) {
            return new WP_Error('not_found', 'Project not found', ['status' => 404]);
        }

        $project->enabled = false;
        $project->save();

        return $project;
    }

    public function destroy()
    {
        $id = $this->input('id');

        $project = Project::find($id);

        if (empty($project)) {
            return new WP_Error('not_found', 'Project not found', ['status' => 404]);
        }

        $project->publications()->delete();
        $project->delete();
    }

    // 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.text" => ["nullable", "string"],
                "modules.content.custom_instructions.images" => ["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.text" => "text",
                "modules.content.custom_instructions.images" => "images",
                "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',
            ]
        ];
    }
    // ----


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