<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Models\Artwork;
use App\Models\DashboardPreference;
use App\Models\Story;
use App\Models\User;
use App\Services\ReceivedCommentsInboxService;
use App\Services\XPService;
use App\Support\AvatarUrl;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
final class DashboardController extends Controller
{
    public function __construct(
        private readonly XPService $xp,
        private readonly ReceivedCommentsInboxService $receivedCommentsInbox,
    ) {}

    public function index(Request $request)
    {
        $user = $request->user();
        $xpSummary = $this->xp->summary((int) $user->id);
        $artworksCount = Artwork::query()
            ->where('user_id', $user->id)
            ->whereNull('deleted_at')
            ->count();
        $storiesCount = Story::query()->where('creator_id', $user->id)->count();
        $followersCount = (int) DB::table('user_followers')->where('user_id', $user->id)->count();
        $followingCount = (int) DB::table('user_followers')->where('follower_id', $user->id)->count();
        $favoritesCount = (int) DB::table('artwork_favourites')->where('user_id', $user->id)->count();
        $unreadNotificationsCount = $user->unreadNotifications()->count();
        $receivedCommentsCount = $this->receivedCommentsInbox->unreadCountForUser($user);
        $isCreator = $artworksCount > 0;
        $pinnedSpaces = DashboardPreference::pinnedSpacesForUser($user);

        return view('dashboard', [
            'page_title' => 'Dashboard',
            'dashboard_user_name' => $user?->username ?: $user?->name ?: 'Creator',
            'dashboard_is_creator' => $isCreator,
            'dashboard_level' => $xpSummary['level'],
            'dashboard_rank' => $xpSummary['rank'],
            'dashboard_received_comments_count' => $receivedCommentsCount,
            'dashboard_overview' => [
                'artworks' => $artworksCount,
                'stories' => $storiesCount,
                'followers' => $followersCount,
                'following' => $followingCount,
                'favorites' => $favoritesCount,
                'notifications' => $unreadNotificationsCount,
                'received_comments' => $receivedCommentsCount,
            ],
            'dashboard_preferences' => [
                'pinned_spaces' => $pinnedSpaces,
            ],
        ]);
    }

    public function activity(Request $request): JsonResponse
    {
        $user = $request->user();

        $notificationItems = $user->notifications()
            ->latest()
            ->limit(12)
            ->get()
            ->map(function ($notification): array {
                return [
                    'id' => (string) $notification->id,
                    'type' => 'notification',
                    'message' => $this->notificationMessage((array) $notification->data),
                    'reference_id' => (string) ($notification->id ?? ''),
                    'created_at' => $notification->created_at?->toIso8601String(),
                    'is_unread' => $notification->read_at === null,
                    'actor' => null,
                ];
            });

        $followItems = DB::table('user_followers as uf')
            ->join('users as follower', 'follower.id', '=', 'uf.follower_id')
            ->leftJoin('user_profiles as fp', 'fp.user_id', '=', 'follower.id')
            ->where('uf.user_id', $user->id)
            ->select([
                'uf.follower_id as actor_id',
                'follower.username as actor_username',
                'follower.name as actor_name',
                'fp.avatar_hash as actor_avatar_hash',
                'uf.created_at',
            ])
            ->orderByDesc('uf.created_at')
            ->limit(10)
            ->get()
            ->map(function ($row): array {
                return [
                    'id' => 'follow-' . (string) $row->actor_id . '-' . Carbon::parse((string) $row->created_at)->timestamp,
                    'type' => 'new_follower',
                    'message' => 'started following you',
                    'reference_id' => (string) $row->actor_id,
                    'created_at' => Carbon::parse((string) $row->created_at)->toIso8601String(),
                    'is_unread' => false,
                    'actor' => [
                        'id' => (int) $row->actor_id,
                        'name' => $row->actor_name,
                        'username' => $row->actor_username,
                        'avatar' => AvatarUrl::forUser((int) $row->actor_id, $row->actor_avatar_hash, 64),
                    ],
                ];
            });

        $commentItems = DB::table('artwork_comments as c')
            ->join('artworks as a', 'a.id', '=', 'c.artwork_id')
            ->join('users as commenter', 'commenter.id', '=', 'c.user_id')
            ->leftJoin('user_profiles as cp', 'cp.user_id', '=', 'commenter.id')
            ->where('a.user_id', $user->id)
            ->where('c.user_id', '!=', $user->id)
            ->where('c.is_approved', true)
            ->whereNull('c.deleted_at')
            ->select([
                'c.id as comment_id',
                'c.created_at',
                'a.id as artwork_id',
                'a.slug as artwork_slug',
                'a.title as artwork_title',
                'commenter.id as actor_id',
                'commenter.username as actor_username',
                'commenter.name as actor_name',
                'cp.avatar_hash as actor_avatar_hash',
            ])
            ->orderByDesc('c.created_at')
            ->limit(10)
            ->get()
            ->map(function ($row): array {
                return [
                    'id' => 'comment-' . (string) $row->comment_id,
                    'type' => 'comment',
                    'message' => 'commented on your artwork',
                    'reference_id' => (string) $row->artwork_id,
                    'created_at' => Carbon::parse((string) $row->created_at)->toIso8601String(),
                    'is_unread' => false,
                    'actor' => [
                        'id' => (int) $row->actor_id,
                        'name' => $row->actor_name,
                        'username' => $row->actor_username,
                        'avatar' => AvatarUrl::forUser((int) $row->actor_id, $row->actor_avatar_hash, 64),
                    ],
                    'context' => [
                        'artwork_id' => (int) $row->artwork_id,
                        'artwork_title' => $row->artwork_title,
                        'artwork_url' => '/art/' . $row->artwork_id . '/' . $row->artwork_slug,
                    ],
                ];
            });

        $items = collect()
            ->concat($notificationItems)
            ->concat($followItems)
            ->concat($commentItems)
            ->sortByDesc(fn (array $item) => (string) ($item['created_at'] ?? ''))
            ->take(20)
            ->values();

        return response()->json([
            'data' => $items,
        ]);
    }

    public function analytics(Request $request): JsonResponse
    {
        $user = $request->user();

        $artworksCount = Artwork::query()->where('user_id', $user->id)->count();

        $storyAggregate = Story::query()
            ->where('creator_id', $user->id)
            ->selectRaw('COUNT(*) as total_stories, COALESCE(SUM(views),0) as total_story_views, COALESCE(SUM(likes_count),0) as total_story_likes')
            ->first();

        $stats = $user->statistics;

        $followersCount = (int) ($stats?->followers_count ?? $user->followers()->count());
        $artworkLikes = (int) ($stats?->favorites_received_count ?? 0);
        $storyLikes = (int) ($storyAggregate?->total_story_likes ?? 0);

        return response()->json([
            'data' => [
                'is_creator' => $artworksCount > 0,
                'total_artworks' => $artworksCount,
                'total_stories' => (int) ($storyAggregate?->total_stories ?? 0),
                'total_story_views' => (int) ($storyAggregate?->total_story_views ?? 0),
                'total_followers' => $followersCount,
                'total_likes' => $artworkLikes + $storyLikes,
            ],
        ]);
    }

    public function trendingArtworks(): JsonResponse
    {
        $cacheKey = 'dashboard:trending-artworks:v1';

        $data = Cache::remember($cacheKey, 300, function (): array {
            return Artwork::query()
                ->select('artworks.*')
                ->leftJoin('artwork_stats as s', 's.artwork_id', '=', 'artworks.id')
                ->public()
                ->with(['user.profile', 'stats'])
                ->orderByRaw('COALESCE(s.ranking_score, 0) DESC')
                ->orderByRaw('COALESCE(s.heat_score, 0) DESC')
                ->orderByRaw('COALESCE(s.favorites, 0) DESC')
                ->orderByRaw('COALESCE(s.views, 0) DESC')
                ->orderByRaw('COALESCE(s.comments_count, 0) DESC')
                ->limit(8)
                ->get()
                ->map(function (Artwork $artwork): array {
                    return [
                        'id' => $artwork->id,
                        'title' => $artwork->title,
                        'url' => '/art/' . $artwork->id . '/' . $artwork->slug,
                        'thumbnail' => $artwork->thumbUrl('md') ?? $artwork->thumbnail_url,
                        'likes' => (int) ($artwork->stats?->favorites ?? 0),
                        'views' => (int) ($artwork->stats?->views ?? 0),
                        'comments' => (int) ($artwork->stats?->comments_count ?? 0),
                        'creator' => [
                            'id' => (int) $artwork->user_id,
                            'username' => $artwork->user?->username,
                            'name' => $artwork->user?->name,
                            'url' => $artwork->user?->username ? '/@' . $artwork->user->username : null,
                            'level' => (int) ($artwork->user?->level ?? 1),
                            'rank' => (string) ($artwork->user?->rank ?? 'Newbie'),
                        ],
                    ];
                })
                ->values()
                ->all();
        });

        return response()->json(['data' => $data]);
    }

    public function recommendedCreators(Request $request): JsonResponse
    {
        $user = $request->user();

        $cacheKey = 'dashboard:recommended-creators:' . $user->id . ':v1';

        $data = Cache::remember($cacheKey, 600, function () use ($user): array {
            $followingIds = DB::table('user_followers')
                ->where('follower_id', $user->id)
                ->pluck('user_id')
                ->map(fn ($id) => (int) $id)
                ->all();

            $excludeIds = array_values(array_unique(array_merge([$user->id], $followingIds)));

            return User::query()
                ->from('users')
                ->leftJoin('user_profiles as up', 'up.user_id', '=', 'users.id')
                ->leftJoin('user_statistics as us', 'us.user_id', '=', 'users.id')
                ->where('users.is_active', true)
                ->whereNotIn('users.id', $excludeIds)
                ->whereExists(function ($q): void {
                    $q->select(DB::raw(1))
                        ->from('artworks')
                        ->whereColumn('artworks.user_id', 'users.id')
                        ->where('artworks.is_public', true)
                        ->where('artworks.is_approved', true)
                        ->whereNull('artworks.deleted_at');
                })
                ->select([
                    'users.id',
                    'users.username',
                    'users.name',
                    'users.level',
                    'users.rank',
                    'up.avatar_hash',
                    DB::raw('COALESCE(us.followers_count, 0) as followers_count'),
                    DB::raw('COALESCE(us.uploads_count, 0) as uploads_count'),
                ])
                ->orderByDesc('followers_count')
                ->orderByDesc('uploads_count')
                ->limit(6)
                ->get()
                ->map(function ($row): array {
                    $username = (string) ($row->username ?? '');

                    return [
                        'id' => (int) $row->id,
                        'username' => $username,
                        'name' => $row->name,
                        'url' => $username !== '' ? '/@' . $username : null,
                        'avatar' => AvatarUrl::forUser((int) $row->id, $row->avatar_hash, 64),
                        'level' => (int) ($row->level ?? 1),
                        'rank' => (string) ($row->rank ?? 'Newbie'),
                        'followers_count' => (int) $row->followers_count,
                        'uploads_count' => (int) $row->uploads_count,
                    ];
                })
                ->values()
                ->all();
        });

        return response()->json(['data' => $data]);
    }

    private function notificationMessage(array $payload): string
    {
        $title = trim((string) ($payload['title'] ?? ''));
        if ($title !== '') {
            return $title;
        }

        $message = trim((string) ($payload['message'] ?? ''));
        if ($message !== '') {
            return $message;
        }

        $type = trim((string) ($payload['type'] ?? 'Notification'));
        return $type !== '' ? $type : 'New notification';
    }
}
