<?php

namespace App\Http\Controllers\News;

use App\Http\Controllers\Controller;
use App\Models\User;
use App\Services\News\NewsService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\View;
use cPad\Plugins\News\Models\NewsArticle;
use cPad\Plugins\News\Models\NewsCategory;
use cPad\Plugins\News\Models\NewsTag;
use cPad\Plugins\News\Models\NewsView;

class NewsController extends Controller
{
    public function __construct(private readonly NewsService $news)
    {
    }

    // -----------------------------------------------------------------------
    // Homepage — /news
    // -----------------------------------------------------------------------

    public function index(Request $request): View
    {
        $perPage = config('news.articles_per_page', 12);

        $featured = NewsArticle::with('author', 'category')
            ->published()
            ->editorialOrder()
            ->first();

        $highlightQuery = NewsArticle::with('author', 'category')
            ->published()
            ->editorialOrder();

        if ($featured) {
            $highlightQuery->where('id', '!=', $featured->id);
        }

        $highlights = $highlightQuery->limit(3)->get();
        $excludedIds = collect([$featured?->id])->merge($highlights->pluck('id'))->filter()->all();

        $articles = NewsArticle::with('author', 'category')
            ->published()
            ->when($excludedIds !== [], fn ($query) => $query->whereNotIn('id', $excludedIds))
            ->editorialOrder()
            ->paginate($perPage);

        return view('news.index', [
            'featured' => $featured,
            'highlights' => $highlights,
            'articles' => $articles,
        ] + $this->sidebarData());
    }

    // -----------------------------------------------------------------------
    // Category page — /news/category/{slug}
    // -----------------------------------------------------------------------

    public function category(Request $request, string $slug): View
    {
        $category = NewsCategory::where('slug', $slug)->where('is_active', true)->firstOrFail();
        $perPage  = config('news.articles_per_page', 12);

        $articles   = NewsArticle::with('author', 'category')
            ->published()
            ->byCategory($category->id)
            ->editorialOrder()
            ->paginate($perPage);

        return view('news.category', [
            'category' => $category,
            'articles' => $articles,
        ] + $this->sidebarData());
    }

    // -----------------------------------------------------------------------
    // Tag page — /news/tag/{slug}
    // -----------------------------------------------------------------------

    public function tag(Request $request, string $slug): View
    {
        $tag     = NewsTag::where('slug', $slug)->firstOrFail();
        $perPage = config('news.articles_per_page', 12);

        $articles   = NewsArticle::with('author', 'category')
            ->published()
            ->whereHas('tags', fn ($q) => $q->where('news_tags.slug', $slug))
            ->editorialOrder()
            ->paginate($perPage);

        return view('news.tag', [
            'tag' => $tag,
            'articles' => $articles,
        ] + $this->sidebarData());
    }

    public function archive(Request $request, int $year, int $month): View
    {
        abort_unless($month >= 1 && $month <= 12, 404);

        $perPage = config('news.articles_per_page', 12);
        $articles = NewsArticle::with('author', 'category')
            ->published()
            ->whereYear('published_at', $year)
            ->whereMonth('published_at', $month)
            ->editorialOrder()
            ->paginate($perPage);

        return view('news.archive', [
            'archiveDate' => now()->setDate($year, $month, 1),
            'articles' => $articles,
        ] + $this->sidebarData());
    }

    public function author(Request $request, string $username): View
    {
        $author = User::query()->with('profile')->where('username', $username)->firstOrFail();
        $perPage = config('news.articles_per_page', 12);
        $articles = NewsArticle::with('author', 'category')
            ->published()
            ->where('author_id', $author->id)
            ->editorialOrder()
            ->paginate($perPage);

        return view('news.author', [
            'author' => $author,
            'articles' => $articles,
        ] + $this->sidebarData());
    }

    // -----------------------------------------------------------------------
    // Type page — /news/type/{type}
    // -----------------------------------------------------------------------

    public function type(Request $request, string $type): View
    {
        $typeLabels = \cPad\Plugins\News\Models\NewsArticle::TYPE_LABELS;

        abort_unless(array_key_exists($type, $typeLabels), 404);

        $label   = $typeLabels[$type];
        $perPage = config('news.articles_per_page', 12);

        $articles = NewsArticle::with('author', 'category')
            ->published()
            ->where('type', $type)
            ->editorialOrder()
            ->paginate($perPage);

        return view('news.type', [
            'type'      => $type,
            'typeLabel' => $label,
            'articles'  => $articles,
        ] + $this->sidebarData());
    }

    // -----------------------------------------------------------------------
    // Article page — /news/{slug}
    // -----------------------------------------------------------------------

    public function show(Request $request, string $slug): View
    {
        $article = NewsArticle::with('author.profile', 'category', 'tags', 'relatedEntities')
            ->published()
            ->where('slug', $slug)
            ->firstOrFail();

        // Track view (once per session / IP)
        $this->trackView($request, $article);

        $articleData = $this->news->publicArticleShowData($article, $request->user());

        return view('news.show', [
            'article' => $article,
            'related' => $articleData['related'],
            'relatedEntities' => $articleData['relatedEntities'],
            'comments' => $articleData['comments'],
            'commentsCount' => $articleData['commentsCount'],
        ] + $this->sidebarData());
    }

    // -----------------------------------------------------------------------
    // Helpers
    // -----------------------------------------------------------------------

    private function trackView(Request $request, NewsArticle $article): void
    {
        $ip      = $request->ip();
        $userId  = Auth::id();
        $session = 'news_view_' . $article->id;

        $canReadSession = $request->hasSession() && ! $request->attributes->get('skinbase.session_skipped');

        if ($canReadSession && $request->session()->has($session)) {
            return;
        }

        try {
            NewsView::create([
                'article_id' => $article->id,
                'user_id'    => $userId,
                'ip'         => $ip,
                'created_at' => now(),
            ]);

            $article->incrementViews();
        } catch (\Illuminate\Database\QueryException $e) {
            // Unique constraint violation — duplicate view, skip silently.
            if (($e->errorInfo[1] ?? 0) !== 1062) {
                throw $e;
            }
        }

        if ($canReadSession) {
            $request->session()->put($session, true);
        }
    }

    private function sidebarData(): array
    {
        return $this->news->sidebarData();
    }
}
