<?php

namespace App\Services;

use App\Models\Entry;
use App\Models\EntryReview;
use App\Models\News;
use App\View\Components\EntryCard;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

class ActivityService
{
    private const CACHE_ENTRIES = 300; // seconds.
    private const CACHE_NEWS = 300; // seconds.
    private const CACHE_MESSAGES = 300; // seconds.
    private const CACHE_THREADS = 300; // seconds.
    private const CACHE_CLUBS = 300; // seconds.
    private const CACHE_REVIEWS = 300; // seconds.
    private const ITEMS_PER_TYPE = 15;

    public function getActivities( array $activities = [ 'entries', 'news', 'messages', 'threads', 'clubs', 'reviews' ] ): Collection
    {
        $c = collect();
        if( in_array( 'entries', $activities ) ) {
            $c = $c->merge($this->getEntries());
        }
        if( in_array( 'news', $activities ) ) {
            $c = $c->merge($this->getNews());
        }
        if( in_array( 'messages', $activities ) ) {
            $c = $c->merge($this->getMessages());
        }
        if( in_array( 'threads', $activities ) ) {
            $c = $c->merge($this->getThreads());
        }
        if( in_array( 'clubs', $activities ) ) {
            $c = $c->merge($this->getClubs());
        }
        if( in_array( 'reviews', $activities ) ) {
            $c = $c->merge($this->getReviews());
        }

        return $c->sortByDesc('date')
            ->values()
            ->take(30)
            ->map(function(array $item){
                $obj = (object) $item;
                $obj->date = Carbon::createFromTimestamp($obj->date);
                return $obj;
            });
    }

    private function formatEntry( Entry $entry ): array
    {
        return [
            'type' => 'entry',
            'title' => $entry->complete_title ?? $entry->title,
            'url' => route('entries.show', ['section' => $entry->type, 'entry' => $entry]),
            'image' => $entry->main_image ? \Storage::url($entry->main_image) : null,
            'date' => $entry->created_at->timestamp,
            'author' => $entry->authors->pluck('name')->implode(', '),
            'user_id' => $entry->user_id,
            'badge' => EntryCard::ENTRY_TYPES_BADGE[$entry->type],
            'badge_class' => $entry->type,
            'excerpt' => $entry->description ? \Str::limit(strip_tags($entry->description), 80) : null,
            'meta' => $entry->getRealPlatform()?->name
        ];
    }

    private function formatNews( News $news ): array
    {
        return [
            'type' => 'news',
            'title' => $news->title,
            'url' => route('news.show', ['news' => $news]),
            'image' => $news->gallery()->first() ? \Storage::url($news->gallery()->first()->image) : null,
            'date' => $news->created_at->timestamp,
            'author' => null,
            'user_id' => $news->user_id,
            'badge' => 'News',
            'badge_class' => 'news',
            'excerpt' => $news->description ? \Str::limit(strip_tags($news->description), 80) : null,
            'meta' => $news->category?->name
        ];
    }

    private function formatMessage( object $message ): array
    {
        return [
            'type' => 'message',
            'title' => $message->title,
            'url' => xfRoute('threads/.'   ) . $message->thread_id . '/post-' . $message->post_id,
            'image' => null,
            'date' => $message->post_date,
            'author' => null,
            'user_id' => $message->user_id,
            'badge' => 'Post',
            'badge_class' => 'message',
            'excerpt' => $message->message ? \Str::limit(strip_tags($message->message), 80) : null,
            'meta' => null
        ];

    }

    private function formatThread( object $thread ): array
    {
        return [
            'type' => 'thread',
            'title' => $thread->title,
            'url' => xfRoute('threads/.' ) . $thread->thread_id,
            'image' => null,
            'date' => $thread->post_date,
            'author' => null,
            'user_id' => $thread->user_id,
            'badge' => 'Thread',
            'badge_class' => 'thread',
            'excerpt' => $thread->message ? \Str::limit(strip_tags($thread->message), 80) : null,
            'meta' => null
        ];

    }

    private function formatClub( object $club ): array
    {
        return [
            'type' => 'club',
            'title' => $club->title,
            'url' => xfRoute('forums/.' ) . $club->node_id,
            'image' => null, // TODO: Remplacer par banner_date
            'date' => $club->club_creation_date,
            'author' => null,
            'user_id' => $club->user_id,
            'badge' => 'Club',
            'badge_class' => 'club',
            'excerpt' => $club->description ? \Str::limit(strip_tags($club->description), 80) : null,
            'meta' => null
        ];
    }

    private function formatReview( EntryReview $review ): array
    {
        return [
            'type' => 'review',
            'title' => $review->title,
            'url' => $review->entry()->exists() ? route('entries.show', ['section' => $review->entry->type, 'entry' => $review->entry]) : '',
            'image' => null,
            'date' => $review->created_at->timestamp,
            'author' => null,
            'user_id' => $review->user_id,
            'badge' => 'Review',
            'badge_class' => 'review',
            'excerpt' => $review->description ? \Str::limit(strip_tags($review->description), 80) : null,
            'meta' => $review->entry()->exists() ? ( $review->entry->complete_title ?? $review->entry->title ) : null,
        ];
    }

    private function getEntries(): array
    {
        return Cache::remember('activity_entries', self::CACHE_ENTRIES, function() {
            return Entry::published()
                ->with(['authors', 'game.platform'])
                ->latest('created_at')
                ->limit(self::ITEMS_PER_TYPE)
                ->get()
                ->map($this->formatEntry(...))
                ->toArray();
        });
    }

    private function getNews(): array
    {
        return Cache::remember('activity_news', self::CACHE_NEWS, function() {
            return News::published()
                ->with('gallery')
                ->latest('created_at')
                ->limit(self::ITEMS_PER_TYPE)
                ->get()
                ->map($this->formatNews(...))
                ->toArray();
        });
    }

    private function getMessages(): array
    {
        return Cache::remember('activity_messages', self::CACHE_MESSAGES, function() {
            return DB::connection('xenforo')
                ->table('post')
                ->join('user', 'post.user_id', '=', 'user.user_id')
                ->join('thread', 'post.thread_id', '=', 'thread.thread_id')
                ->where('post.message_state', 'visible')
                ->where('thread.first_post_id', '!=', 'post.post_id')
                ->orderByDesc('post.post_date')
                ->limit(self::ITEMS_PER_TYPE)
                ->select([
                    'thread.title', 'thread.thread_id', 'post.post_id', 'post.post_date',
                    'post.user_id', 'post.message'
                ])
                ->get()
                ->map($this->formatMessage(...))
                ->toArray();
        });
    }

    private function getThreads(): array
    {
        return Cache::remember('activity_threads', self::CACHE_THREADS, function() {
            return DB::connection('xenforo')
                ->table('thread')
                ->join('user', 'thread.user_id', '=', 'user.user_id')
                ->join('post', 'thread.first_post_id', '=', 'post.post_id')
                ->where('thread.discussion_state', 'visible')
                ->where('thread.discussion_type', '!=', 'redirect' )
                ->orderByDesc('thread.post_date')
                ->limit(self::ITEMS_PER_TYPE)
                ->select([
                    'thread.title', 'thread.thread_id', 'thread.post_date', 'thread.user_id',
                    'post.message'
                ])
                ->get()
                ->map($this->formatThread(...))
                ->toArray();
        });
    }

    private function getClubs(): array
    {
        return Cache::remember('activity_clubs', self::CACHE_CLUBS, function() {
            return DB::connection('xenforo')
                ->table('club')
                ->where('club_state', 'visible')
                ->orderByDesc('club_creation_date')
                ->limit(self::ITEMS_PER_TYPE)
                ->select([
                    'club.title', 'club.description', 'club.node_id',
                    'club.club_creation_date', 'club.user_id'
                ])
                ->get()
                ->map($this->formatClub(...))
                ->toArray();
        });
    }

    private function getReviews(): array
    {
        return Cache::remember('activity_reviews', self::CACHE_REVIEWS, function() {
            return EntryReview::with(['entry'])
                ->latest('created_at')
                ->limit(self::ITEMS_PER_TYPE)
                ->get()
                ->map($this->formatReview(...))
                ->toArray();
        });
    }
}
