<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Artwork;
use App\Models\Story;
use App\Models\StoryBookmark;
use App\Services\SocialService;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;

final class SocialCompatibilityController extends Controller
{
    public function __construct(private readonly SocialService $social) {}

    public function like(Request $request): JsonResponse
    {
        $payload = $request->validate([
            'entity_type' => ['required', 'string', 'in:artwork,story'],
            'entity_id' => ['required', 'integer'],
            'state' => ['nullable', 'boolean'],
        ]);

        $state = array_key_exists('state', $payload)
            ? (bool) $payload['state']
            : ! $request->isMethod('delete');

        if ($payload['entity_type'] === 'story') {
            $story = Story::published()->findOrFail((int) $payload['entity_id']);

            $result = $this->social->toggleStoryLike($request->user(), $story, $state);

            return response()->json([
                'ok' => (bool) ($result['ok'] ?? true),
                'liked' => (bool) ($result['liked'] ?? false),
                'likes_count' => (int) ($result['likes_count'] ?? 0),
                'is_liked' => (bool) ($result['liked'] ?? false),
                'stats' => [
                    'likes' => (int) ($result['likes_count'] ?? 0),
                ],
            ]);
        }

        $artworkId = (int) $payload['entity_id'];
        abort_unless(Artwork::public()->published()->whereKey($artworkId)->exists(), 404);

        return app(ArtworkInteractionController::class)->like(
            $request->merge(['state' => $state]),
            $artworkId,
        );
    }

    public function comments(Request $request): JsonResponse
    {
        $payload = $request->validate([
            'entity_type' => ['required', 'string', 'in:artwork,story'],
            'entity_id' => ['required', 'integer'],
            'content' => [$request->isMethod('get') ? 'nullable' : 'required', 'string', 'min:1', 'max:10000'],
            'parent_id' => ['nullable', 'integer'],
        ]);

        if ($payload['entity_type'] === 'story') {
            if ($request->isMethod('get')) {
                $story = Story::published()->findOrFail((int) $payload['entity_id']);

                return response()->json(
                    $this->social->listStoryComments($story, $request->user()?->id, (int) $request->query('page', 1), 20)
                );
            }

            $story = Story::published()->findOrFail((int) $payload['entity_id']);
            $comment = $this->social->addStoryComment(
                $request->user(),
                $story,
                (string) $payload['content'],
                isset($payload['parent_id']) ? (int) $payload['parent_id'] : null,
            );

            return response()->json([
                'data' => $this->social->formatComment($comment, (int) $request->user()->id, true),
            ], 201);
        }

        $artworkId = (int) $payload['entity_id'];
        abort_unless(Artwork::public()->published()->whereKey($artworkId)->exists(), 404);

        if ($request->isMethod('get')) {
            return app(ArtworkCommentController::class)->index($request, $artworkId);
        }

        return app(ArtworkCommentController::class)->store(
            $request->merge([
                'content' => $payload['content'],
                'parent_id' => $payload['parent_id'] ?? null,
            ]),
            $artworkId,
        );
    }

    public function bookmark(Request $request): JsonResponse
    {
        $payload = $request->validate([
            'entity_type' => ['required', 'string', 'in:artwork,story'],
            'entity_id' => ['required', 'integer'],
            'state' => ['nullable', 'boolean'],
        ]);

        $state = array_key_exists('state', $payload)
            ? (bool) $payload['state']
            : ! $request->isMethod('delete');

        if ($payload['entity_type'] === 'story') {
            $story = Story::published()->findOrFail((int) $payload['entity_id']);

            $result = $this->social->toggleStoryBookmark($request->user(), $story, $state);

            return response()->json([
                'ok' => (bool) ($result['ok'] ?? true),
                'bookmarked' => (bool) ($result['bookmarked'] ?? false),
                'bookmarks_count' => (int) ($result['bookmarks_count'] ?? 0),
                'is_bookmarked' => (bool) ($result['bookmarked'] ?? false),
                'stats' => [
                    'bookmarks' => (int) ($result['bookmarks_count'] ?? 0),
                ],
            ]);
        }

        $artworkId = (int) $payload['entity_id'];
        abort_unless(Artwork::public()->published()->whereKey($artworkId)->exists(), 404);

        return app(ArtworkInteractionController::class)->bookmark(
            $request->merge(['state' => $state]),
            $artworkId,
        );
    }

    public function bookmarks(Request $request): JsonResponse
    {
        $payload = $request->validate([
            'entity_type' => ['nullable', 'string', 'in:artwork,story'],
            'per_page' => ['nullable', 'integer', 'min:1', 'max:50'],
        ]);

        $perPage = (int) ($payload['per_page'] ?? 20);
        $userId = (int) $request->user()->id;
        $type = $payload['entity_type'] ?? null;

        $items = collect();

        if ($type === null || $type === 'artwork') {
            $items = $items->concat(
                Schema::hasTable('artwork_bookmarks')
                    ? DB::table('artwork_bookmarks')
                        ->join('artworks', 'artworks.id', '=', 'artwork_bookmarks.artwork_id')
                        ->where('artwork_bookmarks.user_id', $userId)
                        ->where('artworks.is_public', true)
                        ->where('artworks.is_approved', true)
                        ->select([
                            'artwork_bookmarks.created_at as saved_at',
                            'artworks.id',
                            'artworks.title',
                            'artworks.slug',
                        ])
                        ->latest('artwork_bookmarks.created_at')
                        ->limit($perPage)
                        ->get()
                        ->map(fn ($row) => [
                            'type' => 'artwork',
                            'id' => (int) $row->id,
                            'title' => (string) $row->title,
                            'url' => route('art.show', ['id' => (int) $row->id, 'slug' => Str::slug((string) ($row->slug ?: $row->title)) ?: (string) $row->id]),
                            'saved_at' => Carbon::parse($row->saved_at)->toIso8601String(),
                        ])
                    : collect()
            );
        }

        if ($type === null || $type === 'story') {
            $items = $items->concat(
                StoryBookmark::query()
                    ->with('story:id,slug,title')
                    ->where('user_id', $userId)
                    ->latest('created_at')
                    ->limit($perPage)
                    ->get()
                    ->filter(fn (StoryBookmark $bookmark) => $bookmark->story !== null)
                    ->map(fn (StoryBookmark $bookmark) => [
                        'type' => 'story',
                        'id' => (int) $bookmark->story->id,
                        'title' => (string) $bookmark->story->title,
                        'url' => route('stories.show', ['slug' => $bookmark->story->slug]),
                        'saved_at' => $bookmark->created_at?->toIso8601String(),
                    ])
            );
        }

        return response()->json([
            'data' => $items
                ->sortByDesc('saved_at')
                ->take($perPage)
                ->values()
                ->all(),
        ]);
    }
}