<?php

declare(strict_types=1);

namespace App\Domain\Seo;

use App\Models\Article;
use App\Models\Category;
use App\Settings\GeneralSettings;
use App\Settings\SeoSettings;
use Illuminate\Support\Str;

class SeoPresenter
{
    public function __construct(
        protected GeneralSettings $generalSettings,
        protected SeoSettings $seoSettings,
    ) {}

    public function title(?string $title = null): string
    {
        $suffix = $this->seoSettings->meta_title_suffix;

        if ($title === null || $title === '') {
            return $this->generalSettings->site_name;
        }

        return $suffix
            ? "{$title} {$suffix}"
            : "{$title} - {$this->generalSettings->site_name}";
    }

    public function description(?string $description = null): string
    {
        return $description
            ?: ($this->seoSettings->default_description
                ?: ($this->generalSettings->site_description ?? ''));
    }

    public function keywords(?string $keywords = null): ?string
    {
        return $keywords ?: $this->seoSettings->default_keywords;
    }

    /**
     * @return array{title: string, description: string, keywords: ?string, canonical: string, og: array<string, string>, twitter: array<string, string>, jsonld: array<string, mixed>}
     */
    public function forHome(): array
    {
        $canonical = rtrim($this->generalSettings->site_url ?: url('/'), '/') ?: url('/');

        return [
            'title' => $this->title(),
            'description' => $this->description(),
            'keywords' => $this->keywords(),
            'canonical' => $canonical,
            'og' => $this->openGraph(),
            'twitter' => $this->twitterCards(),
            'jsonld' => $this->jsonLd(),
        ];
    }

    /**
     * @return array{title: string, description: string, keywords: ?string, canonical: string, og: array<string, string>, twitter: array<string, string>, jsonld: array<string, mixed>}
     */
    public function forArticle(Article $article): array
    {
        $canonical = url('/show-'.$article->id.'.shtml');

        return [
            'title' => $this->title($article->title),
            'description' => $this->description($article->description),
            'keywords' => $this->keywords($article->keywords),
            'canonical' => $canonical,
            'og' => $this->openGraph($article),
            'twitter' => $this->twitterCards($article),
            'jsonld' => $this->jsonLd($article),
        ];
    }

    /**
     * @return array{title: string, description: string, keywords: ?string, canonical: string, og: array<string, string>, twitter: array<string, string>, jsonld: array<string, mixed>}
     */
    public function forCategory(Category $category): array
    {
        $canonical = $category->publicUrl();
        $rawDescription = $category->description ?: Str::limit(trim(preg_replace('/\s+/', ' ', (string) $category->intro) ?: ''), 160);
        $description = $this->description($rawDescription !== '' ? $rawDescription : null);

        return [
            'title' => $this->title($category->name),
            'description' => $description,
            'keywords' => $this->keywords($category->keywords),
            'canonical' => $canonical,
            'og' => array_filter([
                'og:title' => $this->title($category->name),
                'og:description' => $description,
                'og:url' => $canonical,
                'og:type' => 'website',
                'og:site_name' => $this->generalSettings->site_name,
                'og:locale' => 'zh_CN',
                'og:image' => $category->coverUrl(),
            ]),
            'twitter' => array_filter([
                'twitter:card' => $category->coverUrl() ? 'summary_large_image' : 'summary',
                'twitter:title' => $this->title($category->name),
                'twitter:description' => $description,
                'twitter:image' => $category->coverUrl(),
            ]),
            'jsonld' => $this->jsonLdForCategory($category, $canonical, $description),
        ];
    }

    /**
     * @return array<string, mixed>
     */
    protected function jsonLdForCategory(Category $category, string $canonical, string $description): array
    {
        if (! $this->seoSettings->json_ld_enabled) {
            return [];
        }

        return [
            '@context' => 'https://schema.org',
            '@type' => 'CollectionPage',
            'name' => $category->name,
            'description' => $description,
            'url' => $canonical,
            'isPartOf' => [
                '@type' => 'WebSite',
                'name' => $this->generalSettings->site_name,
                'url' => $this->generalSettings->site_url ?: url('/'),
            ],
        ];
    }

    /**
     * @return array<string, string>
     */
    public function openGraph(?Article $article = null): array
    {
        $title = $this->title($article?->title);
        $description = $this->description($article?->description);
        $url = $article
            ? url('/show-'.$article->id.'.shtml')
            : ($this->generalSettings->site_url ?: url('/'));

        return array_filter([
            'og:title' => $title,
            'og:description' => $description,
            'og:url' => $url,
            'og:type' => $article ? 'article' : 'website',
            'og:site_name' => $this->generalSettings->site_name,
            'og:locale' => 'zh_CN',
            'og:image' => $article?->coverUrl(),
        ]);
    }

    /**
     * @return array<string, string>
     */
    public function twitterCards(?Article $article = null): array
    {
        return array_filter([
            'twitter:card' => 'summary',
            'twitter:title' => $this->title($article?->title),
            'twitter:description' => $this->description($article?->description),
        ]);
    }

    /**
     * @return array<string, mixed>
     */
    public function jsonLd(?Article $article = null): array
    {
        if (! $this->seoSettings->json_ld_enabled) {
            return [];
        }

        if ($article === null) {
            return [
                '@context' => 'https://schema.org',
                '@type' => 'WebSite',
                'name' => $this->generalSettings->site_name,
                'url' => $this->generalSettings->site_url ?: url('/'),
                'description' => $this->description(),
                'potentialAction' => [
                    '@type' => 'SearchAction',
                    'target' => url('/search.shtml').'?keywords={search_term_string}',
                    'query-input' => 'required name=search_term_string',
                ],
            ];
        }

        return [
            '@context' => 'https://schema.org',
            '@type' => 'BlogPosting',
            'headline' => $article->title,
            'description' => $this->description($article->description),
            'datePublished' => optional($article->published_at)?->toIso8601String(),
            'dateModified' => optional($article->updated_at)?->toIso8601String(),
            'author' => [
                '@type' => 'Person',
                'name' => $article->user?->name ?? $article->user?->username,
            ],
            'mainEntityOfPage' => url('/show-'.$article->id.'.shtml'),
        ];
    }
}
