<?php

namespace App\Http\Controllers;

use App\Http\Requests\TrendingPagesRequest;
use App\Http\Resources\GlobalContentResource;
use App\Http\Resources\ListingResource;
use App\Http\Resources\PageListResource;
use App\Http\Resources\PageResource;
use App\Traits\CacheObject;
use App\PageRepository;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Session;
use Mtc\MercuryDataModels\Page;
use Mtc\MercuryDataModels\GlobalContent;
use Mtc\MercuryDataModels\Jobs\TrackResourceView;
use Mtc\MercuryDataModels\Seo404;

class PageController extends Controller
{
    use CacheObject;

    /**
     * Show page detail
     *
     * @param Request $request
     * @param string $pageSlug
     * @return PageResource|Response
     */
    public function show(Request $request, string $pageSlug): PageResource|Response|JsonResponse
    {
        // Not using binding in route as to allow for Seo Redirect middleware
        /** @var Page $page */
        $page = Page::query()->where('slug', $pageSlug)->firstOrFail();
        if ($page->status !== 'published' && !$this->withAccessKey($request, $page)) {
            return response('Access denied', 401);
        }

        // Version without access param
        if ($request->filled('v') && !$this->withAccessKey($request, $page)) {
            return response('Access denied', 401);
        }

        if ($this->withAccessKey($request, $page)) {
            $this->clearCache('page-view-' . $request->getRequestUri());
        }

        if ($this->restrictedPage($page, $request->input())) {
            return response('Access denied', 401);
        }

        if ($this->beforePublishDate($page, $request->input()) && !$this->withAccessKey($request, $page)) {
            return response('Page not found', 404);
        }

        // Track page view only for published pages without access key (not preview/draft)
        if ($page->status === 'published' && !$this->withAccessKey($request, $page)) {
            TrackResourceView::trackHit($page);
        }

        return $this->cache(
            'page-view-' . $request->getRequestUri(), // request uri instead of page slug for access and version params
            1,
            fn () => new PageResource($page)->toResponse($request)
        );
    }

    public function globalContent(Request $request, $slug)
    {
        // Cache disabled as causes issues with returning empty content
        return $this->cache("global-content-$slug", 1, fn () => new GlobalContentResource(GlobalContent::query()
            ->where('slug', $slug)
            ->firstOrFail())->toResponse($request));
    }

    public function track404(Request $request)
    {
        if (!empty($request->header('x-path'))) {
            Seo404::track($request->header('x-path'));
        }
        return \response('received');
    }

    private function restrictedPage(Page $page, array $input): bool
    {
        if (empty($page->password)) {
            return false;
        }

        $submitted_password = $input['password'] ?? Session::get('page-auth-password');
        if ($submitted_password === $page->password) {
            Session::put('page-auth-password', $submitted_password);
        }

        return $submitted_password !== $page->password;
    }

    private function beforePublishDate(Page $page, array $input): bool
    {
        if (empty($page->published_at)) {
            return false;
        }

        return $page->published_at->gt(Carbon::now());
    }

    public function paginatedListing(Request $request, PageRepository $pageRepository, $type = null): array
    {
        $categories = null;
        $tags = null;
        $featured = null;
        $excludeIds = [];
        $page = Page::query()->where('slug', $type)->active()->first();

        if ($request->boolean('highlightLatest')) {
            $latestArticle = $pageRepository->latestArticle($type);
            if ($latestArticle) {
                $featured = collect([$latestArticle]);
                $excludeIds = [$latestArticle->id];
            }
        }

        $listing = $pageRepository->listing(
            $type,
            $request->input('perPage') ?? 15,
            'published_at',
            $request->input(),
            true,
            $excludeIds
        );

        if ($request->input('withCategories')) {
            $categories = $pageRepository->getCategories($type);
        }

        if ($request->input('withTags')) {
            $tags = $pageRepository->getTags($type);
        }

        if ($request->input('withFeatured') && !$request->boolean('highlightLatest')) {
            $featured = $pageRepository->featured($type, 3, $request->input());
        }

        return [
            'listing' => new ListingResource($listing, $categories, $tags, $featured),
            'page' => $page ? new PageResource($page) : null,
        ];
    }

    public function trending(TrendingPagesRequest $request, PageRepository $pageRepository): JsonResponse
    {
        $pages = $pageRepository->trending(
            type:       $request->input('type'),
            pageCount:  (int) $request->input('page_count', 5),
            days:       $request->has('days') ? (int) $request->input('days') : null,
            pageSlug:   $request->input('page_slug'),
            filterType:  $request->input('filter_type', 'author'),
            includeSlug: (bool) $request->input('include_slug', false),
        );

        return response()->json(new PageListResource($pages));
    }

    private function withAccessKey(Request $request, Page $page): bool
    {
        return $request->input('a') === base64_encode($page?->id . '-' . $page?->slug);
    }
}
