<?php

namespace App\Controllers;

use App\Models\ArticleModel;

class Articles extends BaseController
{
    public function index()
    {
        $search = trim((string) $this->request->getGet("search"));
        $model = new ArticleModel();
        if ($search !== "") {
            $model
                ->groupStart()
                ->like("title", $search)
                ->orLike("slug", $search)
                ->orLike("category", $search)
                ->orLike("focus_keyword", $search)
                ->groupEnd();
        }

        return view("admin/articles/index", [
            "articles" => $model
                ->orderBy("is_featured", "DESC")
                ->orderBy("published_at", "DESC")
                ->orderBy("created_at", "DESC")
                ->findAll(250),
            "search" => $search,
            "metrics" => [
                "total" => (new ArticleModel())->countAll(),
                "published" => (new ArticleModel())
                    ->where("is_published", 1)
                    ->countAllResults(),
                "drafts" => (new ArticleModel())
                    ->where("is_published", 0)
                    ->countAllResults(),
                "featured" => (new ArticleModel())
                    ->where("is_featured", 1)
                    ->countAllResults(),
            ],
        ]);
    }

    public function create()
    {
        if ($this->request->getMethod() === "post") {
            return $this->saveArticle();
        }

        return view("admin/articles/form", [
            "article" => null,
            "mode" => "create",
            "categories" => $this->categories(),
            "themes" => $this->themes(),
        ]);
    }

    public function show($id)
    {
        $article = (new ArticleModel())->find((int) $id);
        if (!$article) {
            return $this->notFound();
        }

        return view("admin/articles/show", ["article" => $article]);
    }

    public function edit($id)
    {
        $article = (new ArticleModel())->find((int) $id);
        if (!$article) {
            return $this->notFound();
        }
        if ($this->request->getMethod() === "post") {
            return $this->saveArticle((int) $id);
        }

        return view("admin/articles/form", [
            "article" => $article,
            "mode" => "edit",
            "categories" => $this->categories(),
            "themes" => $this->themes(),
        ]);
    }

    public function delete($id)
    {
        $article = (new ArticleModel())->find((int) $id);
        if (!$article) {
            return $this->notFound();
        }

        (new ArticleModel())->delete((int) $id);
        return redirect()
            ->to(base_url("admin/articles"))
            ->with("success", $article["title"] . " was deleted.");
    }

    private function saveArticle(?int $id = null)
    {
        $rules = [
            "title" => "required|min_length[10]|max_length[180]",
            "slug" =>
                "required|min_length[5]|max_length[180]|regex_match[/^[a-z0-9]+(?:-[a-z0-9]+)*$/]",
            "category" =>
                "required|in_list[Logo Planning,Logo Design,Logo Redesign,Brand Strategy]",
            "excerpt" => "required|min_length[40]|max_length[700]",
            "content" => "required|min_length[300]|max_length[60000]",
            "meta_title" => "required|min_length[20]|max_length[180]",
            "meta_description" => "required|min_length[60]|max_length[320]",
            "focus_keyword" => "permit_empty|max_length[160]",
            "author_name" => "required|max_length[120]",
            "reading_minutes" =>
                "required|integer|greater_than[0]|less_than[61]",
            "theme" => "required|in_list[orange,lime,blue,rose]",
            "published_at" => "permit_empty|max_length[20]",
        ];
        if (!$this->validate($rules)) {
            return redirect()
                ->back()
                ->withInput()
                ->with("error", implode(" ", $this->validator->getErrors()));
        }

        $slug = strtolower(trim((string) $this->request->getPost("slug")));
        $duplicate = (new ArticleModel())->where("slug", $slug);
        if ($id !== null) {
            $duplicate->where("id !=", $id);
        }
        if ($duplicate->first()) {
            return redirect()
                ->back()
                ->withInput()
                ->with("error", "That article URL is already in use.");
        }

        $published = $this->request->getPost("is_published") ? 1 : 0;
        $publishedAt = trim((string) $this->request->getPost("published_at"));
        if ($publishedAt !== "") {
            $publishedTimestamp = strtotime($publishedAt);
            if ($publishedTimestamp === false) {
                return redirect()
                    ->back()
                    ->withInput()
                    ->with("error", "Enter a valid publish date and time.");
            }
            $publishedAt = date("Y-m-d H:i:s", $publishedTimestamp);
        } elseif ($published) {
            $publishedAt =
                $id !== null
                    ? (new ArticleModel())->find($id)["published_at"] ??
                        date("Y-m-d H:i:s")
                    : date("Y-m-d H:i:s");
        } else {
            $publishedAt = null;
        }

        $data = [
            "title" => trim((string) $this->request->getPost("title")),
            "slug" => $slug,
            "category" => (string) $this->request->getPost("category"),
            "excerpt" => trim((string) $this->request->getPost("excerpt")),
            "content" => $this->sanitizeContent(
                (string) $this->request->getPost("content"),
            ),
            "meta_title" => trim(
                (string) $this->request->getPost("meta_title"),
            ),
            "meta_description" => trim(
                (string) $this->request->getPost("meta_description"),
            ),
            "focus_keyword" => trim(
                (string) $this->request->getPost("focus_keyword"),
            ),
            "author_name" => trim(
                (string) $this->request->getPost("author_name"),
            ),
            "reading_minutes" => (int) $this->request->getPost(
                "reading_minutes",
            ),
            "theme" => (string) $this->request->getPost("theme"),
            "is_featured" => $this->request->getPost("is_featured") ? 1 : 0,
            "is_published" => $published,
            "published_at" => $publishedAt,
        ];

        $articles = new ArticleModel();
        if ($id === null) {
            $id = (int) $articles->insert($data);
        } else {
            $articles->update($id, $data);
        }

        return redirect()
            ->to(base_url("admin/articles/" . $id))
            ->with(
                "success",
                $published
                    ? "Article saved and published."
                    : "Article saved as a draft.",
            );
    }

    private function sanitizeContent(string $content): string
    {
        $content = strip_tags(
            $content,
            "<p><h2><h3><h4><ul><ol><li><strong><em><blockquote><a><hr>",
        );
        $content = preg_replace(
            '/\s+on[a-z]+\s*=\s*(".*?"|\'.*?\'|[^\s>]+)/i',
            "",
            $content,
        );
        $content = preg_replace(
            '/href\s*=\s*(["\'])\s*javascript:.*?\1/i',
            'href="#"',
            $content,
        );

        return trim((string) $content);
    }

    private function categories(): array
    {
        return [
            "Logo Planning",
            "Logo Design",
            "Logo Redesign",
            "Brand Strategy",
        ];
    }

    private function themes(): array
    {
        return [
            "orange" => "Orange / energetic",
            "lime" => "Lime / progressive",
            "blue" => "Blue / trustworthy",
            "rose" => "Rose / editorial",
        ];
    }

    private function notFound()
    {
        return redirect()
            ->to(base_url("admin/articles"))
            ->with("error", "Article not found.");
    }
}
