<?php

declare(strict_types=1);

namespace App\Framework\Core\ValueObjects\StructuredData;

use App\Framework\Core\ValueObjects\LinkCollection;
use App\Framework\Http\Url\Url;

/**
 * WebPage Structured Data
 *
 * Schema.org WebPage type for page-level metadata.
 * Framework-compliant readonly value object with type enum support.
 *
 * @see https://schema.org/WebPage
 * @psalm-immutable
 */
final readonly class WebPage implements StructuredData
{
    /**
     * @param Url $url Page URL
     * @param string $name Page title/name
     * @param WebPageType $type WebPage type variant
     * @param string|null $description Page description
     * @param LinkCollection|null $breadcrumb Breadcrumb navigation
     * @param \DateTimeImmutable|null $datePublished Publication date
     * @param \DateTimeImmutable|null $dateModified Last modification date
     * @param string|null $inLanguage Language code (e.g., 'en', 'de')
     * @param array<string> $keywords SEO keywords
     */
    public function __construct(
        public Url $url,
        public string $name,
        public WebPageType $type = WebPageType::WEB_PAGE,
        public ?string $description = null,
        public ?LinkCollection $breadcrumb = null,
        public ?\DateTimeImmutable $datePublished = null,
        public ?\DateTimeImmutable $dateModified = null,
        public ?string $inLanguage = null,
        public array $keywords = []
    ) {}

    public function toJsonLd(): array
    {
        $data = [
            '@context' => 'https://schema.org',
            '@type' => $this->type->value,
            'url' => $this->url->toString(),
            'name' => $this->name,
        ];

        if ($this->description !== null) {
            $data['description'] = $this->description;
        }

        if ($this->breadcrumb !== null && !$this->breadcrumb->isEmpty()) {
            $data['breadcrumb'] = $this->buildBreadcrumbList();
        }

        if ($this->datePublished !== null) {
            $data['datePublished'] = $this->datePublished->format('c');
        }

        if ($this->dateModified !== null) {
            $data['dateModified'] = $this->dateModified->format('c');
        }

        if ($this->inLanguage !== null) {
            $data['inLanguage'] = $this->inLanguage;
        }

        if (!empty($this->keywords)) {
            $data['keywords'] = implode(', ', $this->keywords);
        }

        return $data;
    }

    public function toScript(): string
    {
        $json = json_encode($this->toJsonLd(), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

        return '<script type="application/ld+json">' . $json . '</script>';
    }

    /**
     * Build breadcrumb list for JSON-LD
     */
    private function buildBreadcrumbList(): array
    {
        $items = [];
        $position = 1;

        foreach ($this->breadcrumb as $link) {
            $href = $link instanceof \App\Framework\Core\ValueObjects\AccessibleLink
                ? $link->getHref()
                : $link->getHref();

            $name = $link instanceof \App\Framework\Core\ValueObjects\AccessibleLink
                ? ($link->baseLink->text ?? $href)
                : ($link->text ?? $href);

            $items[] = [
                '@type' => 'ListItem',
                'position' => $position,
                'name' => $name,
                'item' => $href
            ];

            $position++;
        }

        return [
            '@type' => 'BreadcrumbList',
            'itemListElement' => $items
        ];
    }

    /**
     * With description (immutable)
     */
    public function withDescription(?string $description): self
    {
        return new self(
            url: $this->url,
            name: $this->name,
            type: $this->type,
            description: $description,
            breadcrumb: $this->breadcrumb,
            datePublished: $this->datePublished,
            dateModified: $this->dateModified,
            inLanguage: $this->inLanguage,
            keywords: $this->keywords
        );
    }

    /**
     * With breadcrumb (immutable)
     */
    public function withBreadcrumb(?LinkCollection $breadcrumb): self
    {
        return new self(
            url: $this->url,
            name: $this->name,
            type: $this->type,
            description: $this->description,
            breadcrumb: $breadcrumb,
            datePublished: $this->datePublished,
            dateModified: $this->dateModified,
            inLanguage: $this->inLanguage,
            keywords: $this->keywords
        );
    }

    /**
     * With keywords (immutable)
     */
    public function withKeywords(string ...$keywords): self
    {
        return new self(
            url: $this->url,
            name: $this->name,
            type: $this->type,
            description: $this->description,
            breadcrumb: $this->breadcrumb,
            datePublished: $this->datePublished,
            dateModified: $this->dateModified,
            inLanguage: $this->inLanguage,
            keywords: $keywords
        );
    }
}
