<?php

declare(strict_types=1);

namespace App\Services\RSS;

use Illuminate\Http\Response;
use Illuminate\Support\Collection;

/**
 * RSSFeedBuilder
 *
 * Responsible for:
 *  - normalising feed items from Eloquent collections
 *  - enforcing feed limits (max 20 items)
 *  - rendering RSS 2.0 XML via the rss.channel Blade template
 *  - returning a properly typed HTTP Response
 */
final class RSSFeedBuilder
{
    /** Hard item limit per feed (spec §7). */
    public const FEED_LIMIT = 20;

    // ── Public builders ───────────────────────────────────────────────────────

    /**
     * Build an RSS 2.0 Response from an Artwork Eloquent collection.
     * Artworks must have 'user' and 'categories' relations preloaded.
     */
    public function buildFromArtworks(
        string     $channelTitle,
        string     $channelDescription,
        string     $feedUrl,
        Collection $artworks,
    ): Response {
        $items = $artworks->take(self::FEED_LIMIT)->map(fn ($a) => $this->artworkToItem($a));

        return $this->buildResponse($channelTitle, $channelDescription, url('/'), $feedUrl, $items);
    }

    /**
     * Build an RSS 2.0 Response from a BlogPost Eloquent collection.
     * Posts must have 'author' relation preloaded.
     */
    public function buildFromBlogPosts(
        string     $channelTitle,
        string     $channelDescription,
        string     $feedUrl,
        Collection $posts,
    ): Response {
        $items = $posts->take(self::FEED_LIMIT)->map(fn ($p) => $this->blogPostToItem($p));

        return $this->buildResponse($channelTitle, $channelDescription, url('/blog'), $feedUrl, $items);
    }

    // ── Private helpers ───────────────────────────────────────────────────────

    private function buildResponse(
        string     $channelTitle,
        string     $channelDescription,
        string     $channelLink,
        string     $feedUrl,
        Collection $items,
        ?string    $canonicalUrl = null,
    ): Response {
        $xml = view('rss.channel', [
            'channelTitle'       => trim($channelTitle) . ' — Skinbase',
            'channelDescription' => $channelDescription,
            'channelLink'        => $channelLink,
            'feedUrl'            => $feedUrl,
            'canonicalUrl'       => $canonicalUrl ?: $feedUrl,
            'items'              => $items,
            'buildDate'          => now()->toRfc2822String(),
        ])->render();

        return response($xml, 200, [
            'Content-Type'  => 'application/rss+xml; charset=utf-8',
            'Cache-Control' => 'public, max-age=300',
        ]);
    }

    /** Convert an Artwork model to an RSS item array. */
    private function artworkToItem(object $artwork): array
    {
        $link  = url('/art/' . $artwork->id . '/' . ($artwork->slug ?? ''));
        $thumb = method_exists($artwork, 'thumbUrl') ? $artwork->thumbUrl('sm') : null;

        // Primary category from eagerly loaded relation (avoid N+1)
        $primaryCategory = ($artwork->relationLoaded('categories'))
            ? $artwork->categories->first()
            : null;

        // Build HTML description embedded in CDATA
        $descParts = [];
        if ($thumb) {
            $descParts[] = '<img src="' . htmlspecialchars($thumb, ENT_XML1) . '" '
                . 'alt="' . htmlspecialchars((string) $artwork->title, ENT_XML1) . '" />';
        }
        if (!empty($artwork->description)) {
            $descParts[] = '<p>' . htmlspecialchars(strip_tags((string) $artwork->description), ENT_XML1) . '</p>';
        }

        return [
            'title'       => (string) $artwork->title,
            'link'        => $link,
            'guid'        => $link,
            'description' => implode('', $descParts),
            'pubDate'     => $artwork->published_at?->toRfc2822String(),
            'author'      => $artwork->user?->username ?? 'Unknown',
            'category'    => $primaryCategory?->name,
            'enclosure'   => $thumb ? [
                'url'    => $thumb,
                'length' => 0,
                'type'   => 'image/jpeg',
            ] : null,
        ];
    }

    /** Convert a BlogPost model to an RSS item array. */
    private function blogPostToItem(object $post): array
    {
        $link    = url('/blog/' . $post->slug);
        $excerpt = $post->excerpt ?? strip_tags((string) ($post->body ?? ''));

        return [
            'title'       => (string) $post->title,
            'link'        => $link,
            'guid'        => $link,
            'description' => $excerpt,
            'pubDate'     => $post->published_at?->toRfc2822String(),
            'author'      => $post->author?->username ?? 'Skinbase',
            'category'    => null,
            'enclosure'   => !empty($post->featured_image) ? [
                'url'    => $post->featured_image,
                'length' => 0,
                'type'   => 'image/jpeg',
            ] : null,
        ];
    }
}
