<?php

namespace OtomaticAi\Controllers;

use OtomaticAi\Models\Project;
use OtomaticAi\Models\Publication;
use OtomaticAi\Models\ThumbnailTask;
use OtomaticAi\Utils\Planning;
use OtomaticAi\Utils\Scheduler;
use OtomaticAi\Vendors\Carbon\Carbon;
use OtomaticAi\Vendors\Illuminate\Database\Eloquent\Builder;
use OtomaticAi\Vendors\Illuminate\Support\Arr;
use OtomaticAi\Vendors\Illuminate\Support\Str;
use OtomaticAi\Vendors\Illuminate\Validation\Rule;

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

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

        $project = Project::with('persona')->find($this->input("project"));

        if ($project) {
            $publications = $this->makeQuery($project);
            $publications = $publications->paginate(20, ['*'], 'page', $this->input('page', 1))->onEachSide(1);
        } else {
            $publications = [];
        }

        $this->response([
            "project" => $project,
            "publications" => $publications
        ]);
    }

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

        $this->validate([
            "publications.all" => ["boolean"],
            "publications.current" => ["boolean"],
            "publications.selected" => ["array"],
            "filters" => ["required", "array"],
            "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"],
        ]);

        // make publication query
        $project = Project::find($this->input("filters.project"));
        $publications = $this->makeQuery($project, $this->input("filters"));
        $publications = $publications->select("id");

        // filter selected
        if ($this->input("publications.all", false)) {
            $publications = $publications->get();
        } else if (Arr::get($this->request, "publications.current", false)) {
            $page = $this->input("filters.page", 1) - 1;
            $publications = $publications->take(20)->skip($page * 20)->get();
        } else if (!empty(Arr::get($this->request, "publications.selected", []))) {
            $publications = $publications->whereIn("id", $this->input("publications.selected", []))->get();
        } else {
            $this->emptyResponse();
        }

        $publications = $publications->pluck("id");

        if ($publications->count() > 0) {

            if (!$this->input("planning.enabled", false)) {
                $publications->each(function ($id) {
                    Publication::where("id", $id)
                        ->update([
                            "published_at" => Carbon::now(),
                        ]);
                });
            } else {
                $planning = new Planning($publications);
                $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 ($id, $date) {
                        Publication::where("id", $id)
                            ->update([
                                "published_at" => $date,
                            ]);
                    });
            }

            $project->refreshMetrics();
        }

        $this->emptyResponse();
    }

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

        $this->validate([
            "publications.all" => ["boolean"],
            "publications.current" => ["boolean"],
            "publications.selected" => ["array"],
            "filters" => ["required", "array"],
            "model" => ["required", "string"],
            "override" => ["boolean"],
        ]);

        // make publication query
        $project = Project::find($this->input("filters.project"));
        $publications = $this->makeQuery($project, $this->input("filters"));
        $publications = $publications->select(["id", "post_id", "status"]);

        // filter selected
        if ($this->input("publications.all", false)) {
            $publications = $publications->get();
        } else if (Arr::get($this->request, "publications.current", false)) {
            $page = $this->input("filters.page", 1) - 1;
            $publications = $publications->take(20)->skip($page * 20)->get();
        } else if (!empty(Arr::get($this->request, "publications.selected", []))) {
            $publications = $publications->whereIn("id", $this->input("publications.selected", []))->get();
        } else {
            $this->emptyResponse();
        }

        if ($publications->count() > 0) {
            $publications->each(function ($publication) {
                if ($publication->post_id !== null && $publication->status === "success") {
                    $thumbnailTask = new ThumbnailTask();
                    $thumbnailTask->publication()->associate($publication);
                    $thumbnailTask->model = $this->input("model");
                    $thumbnailTask->override = $this->input("override", false);
                    if ($thumbnailTask->save()) {
                        Scheduler::single("generate_thumbnail", [$thumbnailTask->id]);
                    }
                }
            });
        }

        $this->emptyResponse();
    }

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

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

        $publication = Publication::idle()->find($this->input('publication'));
        if ($publication) {
            $publication->published_at = Carbon::now();
            $publication->save();
        }

        $this->emptyResponse();
    }

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

        $this->validate([
            "publications.all" => ["boolean"],
            "publications.current" => ["boolean"],
            "publications.selected" => ["array"],
            "filters" => ["required", "array"],
        ]);

        // make publication query
        $project = Project::find($this->input("filters.project"));
        $publications = $this->makeQuery($project, $this->input("filters"));

        // filter selected
        if ($this->input("publications.all", false)) {
            $publications = $publications->get();
        } else if (Arr::get($this->request, "publications.current", false)) {
            $page = $this->input("filters.page", 1) - 1;
            $publications = $publications->take(20)->skip($page * 20);
        } else if (!empty(Arr::get($this->request, "publications.selected", []))) {
            $publications = $publications->whereIn("id", $this->input("publications.selected", []));
        } else {
            $this->emptyResponse();
        }

        $ids = $publications->pluck("id")->toArray();
        if (count($ids) > 0) {
            Publication::idle()->whereIn("id", $ids)->update([
                "published_at" => Carbon::now(),
            ]);
        }

        $this->emptyResponse();
    }

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

        $this->validate([
            "publications.all" => ["boolean"],
            "publications.current" => ["boolean"],
            "publications.selected" => ["array"],
            "filters" => ["required", "array"],
        ]);

        // make publication query
        $project = Project::find($this->input("filters.project"));
        $publications = $this->makeQuery($project, $this->input("filters"));

        // filter selected
        if ($this->input("publications.all", false)) {
            $publications = $publications->get();
        } else if (Arr::get($this->request, "publications.current", false)) {
            $page = $this->input("filters.page", 1) - 1;
            $publications = $publications->take(20)->skip($page * 20);
        } else if (!empty(Arr::get($this->request, "publications.selected", []))) {
            $publications = $publications->whereIn("id", $this->input("publications.selected", []));
        } else {
            $this->emptyResponse();
        }

        // get the urls
        $urls = [];
        $publications->each(function ($publication) use (&$urls) {
            $url = $publication->display_link;
            if (!empty($url)) {
                $urls[] = $url;
            }
        });

        $this->response($urls);
    }

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

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

        $publication = Publication::failed()->find($this->input('publication'));
        if ($publication) {
            $publication->status = 'idle';
            $publication->published_at = Carbon::now();
            $publication->save();
        }

        $this->emptyResponse();
    }

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

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

        $publication = Publication::published()->find($this->input('publication'));
        if ($publication) {
            $publication->status = 'idle';
            $publication->published_at = Carbon::now();
            $publication->save();
        }

        $this->emptyResponse();
    }

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

        $this->validate([
            "publications.all" => ["boolean"],
            "publications.current" => ["boolean"],
            "publications.selected" => ["array"],
            "filters" => ["required", "array"],
        ]);

        // make publication query
        $project = Project::find($this->input("filters.project"));
        $publications = $this->makeQuery($project, $this->input("filters"));

        // filter selected
        if ($this->input("publications.all", false)) {
            $publications = $publications->get();
        } else if (Arr::get($this->request, "publications.current", false)) {
            $page = $this->input("filters.page", 1) - 1;
            $publications = $publications->take(20)->skip($page * 20);
        } else if (!empty(Arr::get($this->request, "publications.selected", []))) {
            $publications = $publications->whereIn("id", $this->input("publications.selected", []));
        } else {
            $this->emptyResponse();
        }

        $ids = $publications->pluck("id")->toArray();
        $projectsIds = Publication::select('project_id')->whereIn("id", $ids)->get();
        $now = Carbon::now();
        if (count($ids) > 0) {
            Publication::whereIn("id", $ids)->where(function (Builder $query) {
                return $query->published()->orWhere->failed();
            })->update([
                "status" => "idle",
                "published_at" => $now,
            ]);

            // refresh project metrics
            if ($projectsIds->count() > 0) {
                $projects = Project::where('id', $projectsIds->pluck('project_id')->toArray())->get();
                foreach ($projects as $project) {
                    $project->refreshMetrics();
                }
            }
        }

        $this->emptyResponse();
    }

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

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

        $publication = Publication::find($this->input('publication'));
        if ($publication) {
            $publication->delete();
        }

        $this->emptyResponse();
    }

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

        $this->validate([
            "publications.all" => ["boolean"],
            "publications.current" => ["boolean"],
            "publications.selected" => ["array"],
            "filters" => ["required", "array"],
        ]);

        // make publication query
        $project = Project::find($this->input("filters.project"));
        $publications = $this->makeQuery($project, $this->input("filters"));

        // filter selected
        if ($this->input("publications.all", false)) {
            $publications = $publications->get();
        } else if (Arr::get($this->request, "publications.current", false)) {
            $page = $this->input("filters.page", 1) - 1;
            $publications = $publications->take(20)->skip($page * 20);
        } else if (!empty(Arr::get($this->request, "publications.selected", []))) {
            $publications = $publications->whereIn("id", $this->input("publications.selected", []));
        } else {
            $this->emptyResponse();
        }

        $ids = $publications->pluck("id")->toArray();
        $projectsIds = Publication::select('project_id')->whereIn("id", $ids)->get();
        if (count($ids) > 0) {
            Publication::whereIn("id", $ids)->delete();

            // refresh project metrics
            if ($projectsIds->count() > 0) {
                $projects = Project::where('id', $projectsIds->pluck('project_id')->toArray())->get();
                foreach ($projects as $project) {
                    $project->refreshMetrics();
                }
            }
        }


        $this->emptyResponse();
    }

    private function makeQuery($project, $filters = [])
    {
        $publications = $project->publications();

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

        // filters
        if (!empty($search = Arr::get($filters, "search", $this->input('search', '')))) {
            $publications->where("title", 'like', '%' . Str::lower($search) . '%');
        }
        if (!empty($status = Arr::get($filters, "status", $this->input('status', '')))) {
            $publications->where("status", $status);
        }

        return $publications;
    }
}
