<?php

namespace App;

use Carbon\Carbon;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\DB;
use Mtc\ContentManager\Models\ContentCategory;
use Mtc\ContentManager\Models\ContentTag;
use Mtc\MercuryDataModels\Page;
use Mtc\MercuryDataModels\ResourceView;

class PageRepository
{
    /**
     * @param string|null $type
     * @param int $limit
     * @param string $orderBy
     * @param array|string|null $filters
     * @param $paginated
     * @return LengthAwarePaginator|Collection
     */
    private const TRENDING_DAYS = 30;

    public function listing(
        ?string $type,
        int $limit = 6,
        string $orderBy = 'published_at',
        array|string|null $filters = [],
        $paginated = false
    ) {
        $query = Page::query()
            ->with(['primaryMediaUse.media', 'categories', 'tags'])
            ->active()
            ->where(fn($query) => $query->whereNull('published_at')->orWhere('published_at', '<=', Carbon::now()))
            ->where('category', $type)
            ->when(
                $filters['category'] ?? null,
                fn(Builder $query) => $query->whereHas(
                    'categories',
                    fn(Builder $indexQuery) => $indexQuery->where('slug', $filters['category'])
                )
            )
            ->when(
                $filters['tag'] ?? null,
                fn(Builder $query) => $query->whereHas(
                    'tags',
                    fn(Builder $indexQuery) => $indexQuery->where('slug', $filters['tag'])
                )
            );

        $this->applyOrdering($query, $orderBy);

        if ($paginated) {
            return $query->paginate($limit);
        } else {
            return $query->take($limit)->get();
        }
    }

    /**
     * Apply ordering to the query based on orderBy parameter
     */
    private function applyOrdering(Builder $query, string $orderBy): void
    {
        match ($orderBy) {
            'popular' => $query
                ->addSelect([
                    'total_view_count' => ResourceView::query()
                        ->select(DB::raw('COALESCE(SUM(hits), 0)'))
                        ->whereColumn('viewable_id', 'pages.id')
                        ->where('viewable_type', 'page')
                ])
                ->orderByDesc('total_view_count'),

            'trending' => $query
                ->addSelect([
                    'trending_view_count' => ResourceView::query()
                        ->select(DB::raw('COALESCE(SUM(hits), 0)'))
                        ->whereColumn('viewable_id', 'pages.id')
                        ->where('viewable_type', 'page')
                        ->where('date', '>=', Carbon::now()->subDays(self::TRENDING_DAYS))
                ])
                ->orderByDesc('trending_view_count'),

            default => $query->orderByDesc($orderBy),
        };
    }

    /**
     * @param string|null $type
     * @return Collection
     */
    public function getCategories(?string $type): Collection
    {
        return ContentCategory::query()
            ->whereHas(
                'pages',
                fn(Builder $query) => $query->where('category', $type)->active()
            )
            ->orderBy('name')
            ->get();
    }

    /**
     * @param string|null $type
     * @return Collection
     */
    public function getTags(?string $type): Collection
    {
        return ContentTag::query()
            ->whereHas(
                'pages',
                fn(Builder $query) => $query->where('category', $type)->active()
            )
            ->orderBy('name')
            ->get();
    }

    /**
     * @param string|null $type
     * @param int $limit
     * @param array|null $filters
     * @return Collection
     */
    public function featured(?string $type, int $limit = 3, ?array $filters = [])
    {
        return Page::query()
            ->with(['primaryMediaUse.media', 'categories', 'tags'])
            ->active()
            ->where('featured', 1)
            ->where('category', $type)
            ->when(
                $filters['category'] ?? null,
                fn(Builder $query) => $query->whereHas(
                    'categories',
                    fn(Builder $indexQuery) => $indexQuery->where('slug', $filters['category'])
                )
            )
            ->when(
                $filters['tag'] ?? null,
                fn(Builder $query) => $query->whereHas(
                    'tags',
                    fn(Builder $indexQuery) => $indexQuery->where('slug', $filters['tag'])
                )
            )
            ->inRandomOrder()
            ->take($limit)
            ->get();
    }
}
