<?php

namespace OtomaticAi\RestControllers;

use OtomaticAi\Models\Project;
use OtomaticAi\Models\Publication;
use OtomaticAi\Models\ThumbnailTask;
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;
use WP_Error;

class PublicationRestController extends RestController
{
    const PER_PAGE = 20;

    public function index()
    {
        $this->validate([
            "project_id" => ["required", "integer"],
            "page" => ["nullable", "integer"],
            "sort_order" => ["nullable", "string"],
            "sort_direction" => ["nullable", "string", Rule::in(["asc", "desc"])],
            "search" => ["nullable", "string"],
            "status" => ["nullable", "string"],
        ]);

        // get the project
        $project = Project::find($this->input('project_id'));
        if (empty($project)) {
            return new WP_Error('not_found', 'Project not found', ['status' => 404]);
        }

        // get the page
        $page = $this->input('page', 1);

        // get the sorting
        $sorting = [
            "order" => $this->input('sort_order', 'published_at'),
            "direction" => $this->input('sort_direction', 'desc'),
        ];

        // get the filters
        $filters = [
            "search" => $this->input('search'),
            "status" => $this->input('status'),
        ];

        // make the query
        $publications = $this->makeQuery($project, $sorting, $filters)->paginate(self::PER_PAGE, ['*'], 'page', $page)->onEachSide(1);
        $publications = $publications->toArray();

        // add meta to the response
        if (!isset($publications['meta'])) {
            $publications['meta'] = [
                "project" => $project->toArray(),
            ];
        }

        return $publications;
    }

    // public function show(WP_REST_Request $request)
    // {
    //     $projectId = $request->get_param('project_id');
    //     $id = $request->get_param('id');

    //     $project = Project::find($projectId);

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

    //     $publication = $project->publications()->find($id);

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

    //     return $publication;
    // }

    public function publish()
    {
        // get the publication
        $publication = Publication::find($this->input('id'));
        if (empty($publication)) {
            return new WP_Error('not_found', 'Publication not found', ['status' => 404]);
        }

        // publish the publication
        if ($publication && $publication->status === "idle") {
            $publication->published_at = Carbon::now();
            $publication->save();
        }

        return $publication;
    }

    public function bulkPublish()
    {
        $this->validate([
            "project_id" => ["required", "integer"],
            "page" => ["nullable", "integer"],
            "sort_order" => ["nullable", "string"],
            "sort_direction" => ["nullable", "string", Rule::in(["asc", "desc"])],
            "search" => ["nullable", "string"],
            "status" => ["nullable", "string"],
        ]);

        // get the project
        $project = Project::find($this->input('project_id'));
        if (empty($project)) {
            return new WP_Error('not_found', 'Project not found', ['status' => 404]);
        }

        // get the page
        $page = $this->input('page', 1);

        // get the sorting
        $sorting = [
            "order" => $this->input('sort_order', 'published_at'),
            "direction" => $this->input('sort_direction', 'desc'),
        ];

        // get the filters
        $filters = [
            "search" => $this->input('search'),
            "status" => $this->input('status'),
        ];

        // make the query
        $publications = $this->makeQuery($project, $sorting, $filters);

        // filter selected
        if ($this->input("publications.all", false)) {
            $publications = $publications->get();
        } else if ($this->input("publications.current", false)) {
            $page = $this->input("filters.page", 1) - 1;
            $publications = $publications->take(self::PER_PAGE)->skip($page * self::PER_PAGE);
        } else if (!empty($this->input("publications.selected", []))) {
            $publications = $publications->whereIn("id", $this->input("publications.selected", []));
        } else {
            return new WP_Error('not_found', 'No publications found', ['status' => 404]);
        }

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

    public function bulkCopyUrls()
    {
        $this->validate([
            "project_id" => ["required", "integer"],
            "page" => ["nullable", "integer"],
            "sort_order" => ["nullable", "string"],
            "sort_direction" => ["nullable", "string", Rule::in(["asc", "desc"])],
            "search" => ["nullable", "string"],
            "status" => ["nullable", "string"],
        ]);

        // get the project
        $project = Project::find($this->input('project_id'));
        if (empty($project)) {
            return new WP_Error('not_found', 'Project not found', ['status' => 404]);
        }

        // get the page
        $page = $this->input('page', 1);

        // get the sorting
        $sorting = [
            "order" => $this->input('sort_order', 'published_at'),
            "direction" => $this->input('sort_direction', 'desc'),
        ];

        // get the filters
        $filters = [
            "search" => $this->input('search'),
            "status" => $this->input('status'),
        ];

        // make the query
        $publications = $this->makeQuery($project, $sorting, $filters);

        // filter selected
        if ($this->input("publications.all", false)) {
            $publications = $publications->get();
        } else if ($this->input("publications.current", false)) {
            $page = $this->input("filters.page", 1) - 1;
            $publications = $publications->take(self::PER_PAGE)->skip($page * self::PER_PAGE);
        } else if (!empty($this->input("publications.selected", []))) {
            $publications = $publications->whereIn("id", $this->input("publications.selected", []));
        } else {
            return new WP_Error('not_found', 'No publications found', ['status' => 404]);
        }

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

        return $urls;
    }

    public function retry()
    {
        // get the publication
        $publication = Publication::find($this->input('id'));
        if (empty($publication)) {
            return new WP_Error('not_found', 'Publication not found', ['status' => 404]);
        }

        // publish the publication
        if ($publication && $publication->status === "failed") {
            $publication->status = 'idle';
            $publication->published_at = Carbon::now();
            $publication->save();
        }

        return $publication;
    }

    public function regenerate()
    {
        // get the publication
        $publication = Publication::find($this->input('id'));
        if (empty($publication)) {
            return new WP_Error('not_found', 'Publication not found', ['status' => 404]);
        }

        // publish the publication
        if ($publication && $publication->status === "success") {
            $publication->status = 'idle';
            $publication->published_at = Carbon::now();
            $publication->save();
        }

        return $publication;
    }

    public function bulkRegenerate()
    {
        $this->validate([
            "project_id" => ["required", "integer"],
            "page" => ["nullable", "integer"],
            "sort_order" => ["nullable", "string"],
            "sort_direction" => ["nullable", "string", Rule::in(["asc", "desc"])],
            "search" => ["nullable", "string"],
            "status" => ["nullable", "string"],
        ]);

        // get the project
        $project = Project::find($this->input('project_id'));
        if (empty($project)) {
            return new WP_Error('not_found', 'Project not found', ['status' => 404]);
        }

        // get the page
        $page = $this->input('page', 1);

        // get the sorting
        $sorting = [
            "order" => $this->input('sort_order', 'published_at'),
            "direction" => $this->input('sort_direction', 'desc'),
        ];

        // get the filters
        $filters = [
            "search" => $this->input('search'),
            "status" => $this->input('status'),
        ];

        // make the query
        $publications = $this->makeQuery($project, $sorting, $filters);

        // filter selected
        if ($this->input("publications.all", false)) {
            $publications = $publications->get();
        } else if ($this->input("publications.current", false)) {
            $page = $this->input("filters.page", 1) - 1;
            $publications = $publications->take(self::PER_PAGE)->skip($page * self::PER_PAGE);
        } else if (!empty($this->input("publications.selected", []))) {
            $publications = $publications->whereIn("id", $this->input("publications.selected", []));
        } else {
            return new WP_Error('not_found', 'No publications found', ['status' => 404]);
        }

        // regenerate the publications
        $ids = $publications->pluck("id")->toArray();
        $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
            $project->refreshMetrics();
        }
    }

    public function bulkRegenerateThumbnail()
    {
        $this->validate([
            "project_id" => ["required", "integer"],
            "page" => ["nullable", "integer"],
            "sort_order" => ["nullable", "string"],
            "sort_direction" => ["nullable", "string", Rule::in(["asc", "desc"])],
            "search" => ["nullable", "string"],
            "status" => ["nullable", "string"],
            "model" => ["required", "string"],
            "override" => ["boolean"],
        ]);

        // get the project
        $project = Project::find($this->input('project_id'));
        if (empty($project)) {
            return new WP_Error('not_found', 'Project not found', ['status' => 404]);
        }

        // get the page
        $page = $this->input('page', 1);

        // get the sorting
        $sorting = [
            "order" => $this->input('sort_order', 'published_at'),
            "direction" => $this->input('sort_direction', 'desc'),
        ];

        // get the filters
        $filters = [
            "search" => $this->input('search'),
            "status" => $this->input('status'),
        ];

        // make the query
        $publications = $this->makeQuery($project, $sorting, $filters);
        $publications = $publications->select(["id", "post_id", "status"]);

        // filter selected
        if ($this->input("publications.all", false)) {
            $publications = $publications->get();
        } else if ($this->input("publications.current", false)) {
            $page = $this->input("filters.page", 1) - 1;
            $publications = $publications->take(self::PER_PAGE)->skip($page * self::PER_PAGE);
        } else if (!empty($this->input("publications.selected", []))) {
            $publications = $publications->whereIn("id", $this->input("publications.selected", []));
        } else {
            return new WP_Error('not_found', 'No publications found', ['status' => 404]);
        }

        // regenerate the publications thumbnail
        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]);
                    }
                }
            });
        }
    }

    public function destroy()
    {
        // get the publication
        $publication = Publication::find($this->input('id'));
        if (empty($publication)) {
            return new WP_Error('not_found', 'Publication not found', ['status' => 404]);
        }

        // publish the publication
        if ($publication) {
            $publication->delete();
        }
    }

    public function bulkDestroy()
    {
        $this->validate([
            "project_id" => ["required", "integer"],
            "page" => ["nullable", "integer"],
            "sort_order" => ["nullable", "string"],
            "sort_direction" => ["nullable", "string", Rule::in(["asc", "desc"])],
            "search" => ["nullable", "string"],
            "status" => ["nullable", "string"],
        ]);

        // get the project
        $project = Project::find($this->input('project_id'));
        if (empty($project)) {
            return new WP_Error('not_found', 'Project not found', ['status' => 404]);
        }

        // get the page
        $page = $this->input('page', 1);

        // get the sorting
        $sorting = [
            "order" => $this->input('sort_order', 'published_at'),
            "direction" => $this->input('sort_direction', 'desc'),
        ];

        // get the filters
        $filters = [
            "search" => $this->input('search'),
            "status" => $this->input('status'),
        ];

        // make the query
        $publications = $this->makeQuery($project, $sorting, $filters);

        // filter selected
        if ($this->input("publications.all", false)) {
            $publications = $publications->get();
        } else if ($this->input("publications.current", false)) {
            $page = $this->input("filters.page", 1) - 1;
            $publications = $publications->take(self::PER_PAGE)->skip($page * self::PER_PAGE);
        } else if (!empty($this->input("publications.selected", []))) {
            $publications = $publications->whereIn("id", $this->input("publications.selected", []));
        } else {
            return new WP_Error('not_found', 'No publications found', ['status' => 404]);
        }

        // delete the publications
        $ids = $publications->pluck("id")->toArray();
        if (count($ids) > 0) {
            Publication::whereIn("id", $ids)->delete();

            // refresh project metrics
            $project->refreshMetrics();
        }
    }

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

        // sort 
        if (!empty($order = Arr::get($sorting, "order"))) {
            $publications->orderBy($order, Arr::get($sorting, "direction", "desc"));
        } else {
            $publications->orderBy("published_at", "desc");
        }

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

        return $publications;
    }
}
