<?php

namespace App\Services\Posts;

use App\Models\Post;
use App\Models\PostSave;
use App\Models\User;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class PostFeedService
{
    private const PER_PAGE = 20;

    // ─────────────────────────────────────────────────────────────────────────
    // Profile feed — pinned posts first, then chronological
    // ─────────────────────────────────────────────────────────────────────────

    public function getProfileFeed(
        User $profileUser,
        ?int $viewerId,
        int $page = 1,
    ): array {
        $baseQuery = Post::with($this->eagerLoads())
            ->where('user_id', $profileUser->id)
            ->visibleTo($viewerId);

        // Pinned posts (always on page 1, regardless of pagination)
        $pinned = (clone $baseQuery)
            ->where('is_pinned', true)
            ->orderBy('pinned_order')
            ->get();

        $paginated = (clone $baseQuery)
            ->orderByDesc('created_at')
            ->paginate(self::PER_PAGE, ['*'], 'page', $page);

        // On page 1, prepend pinned posts (deduplicated)
        $paginatedCollection = $paginated->getCollection();
        if ($page === 1 && $pinned->isNotEmpty()) {
            $pinnedIds = $pinned->pluck('id');
            $rest      = $paginatedCollection->reject(fn ($p) => $pinnedIds->contains($p->id));
            $combined  = $pinned->concat($rest);
        } else {
            $combined = $paginatedCollection->reject(fn ($p) => $p->is_pinned && $page === 1);
        }

        return [
            'data' => $combined->values()->all(),
            'meta' => [
                'total'        => $paginated->total(),
                'current_page' => $paginated->currentPage(),
                'last_page'    => $paginated->lastPage(),
                'per_page'     => $paginated->perPage(),
            ],
        ];
    }

    // ─────────────────────────────────────────────────────────────────────────
    // Following feed (ranked + diversity-limited)
    // ─────────────────────────────────────────────────────────────────────────

    public function getFollowingFeed(
        User $viewer,
        int $page = 1,
        string $filter = 'all',
    ): array {
        $followingIds = DB::table('user_followers')
            ->where('follower_id', $viewer->id)
            ->pluck('user_id')
            ->toArray();

        if (empty($followingIds)) {
            return ['data' => [], 'meta' => ['total' => 0, 'current_page' => $page, 'last_page' => 1, 'per_page' => self::PER_PAGE]];
        }

        $query = Post::with($this->eagerLoads())
            ->whereIn('user_id', $followingIds)
            ->visibleTo($viewer->id)
            ->orderByDesc('created_at');

        if ($filter === 'shares')  $query->where('type', Post::TYPE_ARTWORK_SHARE);
        elseif ($filter === 'text')    $query->where('type', Post::TYPE_TEXT);
        elseif ($filter === 'uploads') $query->where('type', Post::TYPE_UPLOAD);

        $paginated   = $query->paginate(self::PER_PAGE, ['*'], 'page', $page);
        $diversified = $this->applyDiversityPass($paginated->getCollection());

        return [
            'data' => $diversified->values()->all(),
            'meta' => [
                'total'        => $paginated->total(),
                'current_page' => $paginated->currentPage(),
                'last_page'    => $paginated->lastPage(),
                'per_page'     => $paginated->perPage(),
            ],
        ];
    }

    // ─────────────────────────────────────────────────────────────────────────
    // Hashtag feed
    // ─────────────────────────────────────────────────────────────────────────

    public function getHashtagFeed(
        string $tag,
        ?int $viewerId,
        int $page = 1,
    ): array {
        $tag = mb_strtolower($tag);

        $paginated = Post::with($this->eagerLoads())
            ->whereHas('hashtags', fn ($q) => $q->where('tag', $tag))
            ->visibleTo($viewerId)
            ->orderByDesc('created_at')
            ->paginate(self::PER_PAGE, ['*'], 'page', $page);

        return [
            'data' => $paginated->getCollection()->values()->all(),
            'meta' => [
                'total'        => $paginated->total(),
                'current_page' => $paginated->currentPage(),
                'last_page'    => $paginated->lastPage(),
                'per_page'     => $paginated->perPage(),
            ],
        ];
    }

    // ─────────────────────────────────────────────────────────────────────────
    // Saved posts feed
    // ─────────────────────────────────────────────────────────────────────────

    public function getSavedFeed(User $viewer, int $page = 1): array
    {
        $paginated = Post::with($this->eagerLoads())
            ->whereHas('saves', fn ($q) => $q->where('user_id', $viewer->id))
            ->where('status', Post::STATUS_PUBLISHED)
            ->orderByDesc('created_at')
            ->paginate(self::PER_PAGE, ['*'], 'page', $page);

        return [
            'data' => $paginated->getCollection()->values()->all(),
            'meta' => [
                'total'        => $paginated->total(),
                'current_page' => $paginated->currentPage(),
                'last_page'    => $paginated->lastPage(),
                'per_page'     => $paginated->perPage(),
            ],
        ];
    }

    // ─────────────────────────────────────────────────────────────────────────
    // Helpers
    // ─────────────────────────────────────────────────────────────────────────

    /** Eager loads for authenticated/profile feeds. */
    private function eagerLoads(): array
    {
        return [
            'user',
            'user.profile',
            'targets',
            'targets.artwork',
            'targets.artwork.user',
            'targets.artwork.user.profile',
            'reactions',
            'hashtags',
        ];
    }

    /** Eager loads safe for public (trending) feed calls from PostTrendingService. */
    public function publicEagerLoads(): array
    {
        return $this->eagerLoads();
    }

    /**
     * Penalize runs of 5+ posts from the same author by deferring them to the end.
     */
    public function applyDiversityPass(Collection $posts): Collection
    {
        $result = collect(); $deferred = collect(); $runCounts = [];

        foreach ($posts as $post) {
            $uid = $post->user_id;
            $runCounts[$uid] = ($runCounts[$uid] ?? 0) + 1;
            ($runCounts[$uid] <= 5 ? $result : $deferred)->push($post);
        }

        return $result->merge($deferred);
    }

    // ─────────────────────────────────────────────────────────────────────────
    // Formatter
    // ─────────────────────────────────────────────────────────────────────────

    /**
     * Serialize a Post into a JSON-safe array for API responses.
     */
    public function formatPost(Post $post, ?int $viewerId): array
    {
        $artworkData = null;

        if ($post->type === Post::TYPE_ARTWORK_SHARE) {
            $target  = $post->targets->firstWhere('target_type', 'artwork');
            $artwork = $target?->artwork;
            if ($artwork) {
                $artworkData = [
                    'id'        => $artwork->id,
                    'title'     => $artwork->title,
                    'slug'      => $artwork->slug,
                    'thumb_url' => $artwork->thumb_url ?? null,
                    'author'    => [
                        'id'       => $artwork->user->id,
                        'username' => $artwork->user->username,
                        'name'     => $artwork->user->name,
                        'avatar'   => $artwork->user->profile?->avatar_url ?? null,
                    ],
                ];
            }
        }

        $viewerLiked = $viewerSaved = false;
        if ($viewerId) {
            $viewerLiked = $post->reactions->where('user_id', $viewerId)->where('reaction', 'like')->isNotEmpty();
            // saves are lazy-loaded only when needed; check if relation is loaded
            if ($post->relationLoaded('saves')) {
                $viewerSaved = $post->saves->where('user_id', $viewerId)->isNotEmpty();
            } else {
                $viewerSaved = $post->saves()->where('user_id', $viewerId)->exists();
            }
        }

        return [
            'id'               => $post->id,
            'type'             => $post->type,
            'visibility'       => $post->visibility,
            'status'           => $post->status,
            'body'             => $post->body,
            'reactions_count'  => $post->reactions_count,
            'comments_count'   => $post->comments_count,
            'saves_count'      => $post->saves_count,
            'impressions_count'=> $post->impressions_count,
            'is_pinned'        => (bool) $post->is_pinned,
            'pinned_order'     => $post->pinned_order,
            'publish_at'       => $post->publish_at?->toISOString(),
            'viewer_liked'     => $viewerLiked,
            'viewer_saved'     => $viewerSaved,
            'artwork'          => $artworkData,
            'author'           => [
                'id'       => $post->user->id,
                'username' => $post->user->username,
                'name'     => $post->user->name,
                'avatar'   => $post->user->profile?->avatar_url ?? null,
            ],
            'hashtags'   => $post->relationLoaded('hashtags') ? $post->hashtags->pluck('tag')->toArray() : [],
            'meta'       => $post->meta,
            'created_at' => $post->created_at->toISOString(),
            'updated_at' => $post->updated_at->toISOString(),
        ];
    }
}
