<?php

namespace App\Http\Controllers;

use App\Model\Attachment;
use App\Model\Sound;
use App\Model\Story;
use App\Model\StoryView;
use App\Model\User;
use App\Providers\AttachmentServiceProvider;
use App\Providers\StoriesServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use JavaScript;

class StoriesController extends Controller
{
    /**
     * Main story create layout.
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
     */
    public function create()
    {
        if (!getSetting('stories.stories_enabled')) abort(404);
        JavaScript::put(
            [
                'mediaSettings' => [
                    'allowed_file_extensions' => '.'.str_replace(',', ',.', AttachmentServiceProvider::filterExtensions('videosFallback')),
                    'max_file_upload_size' => (int) getSetting('media.max_file_upload_size'),
                    'manual_payments_file_extensions' => '.'.str_replace(',', ',.', AttachmentServiceProvider::filterExtensions('manualPayments')),
                    'manual_payments_excel_icon' => asset('/img/excel-preview.svg'),
                    'manual_payments_pdf_icon' => asset('/img/pdf-preview.svg'),
                    'initUploader' => (!Auth::user()->verification || (Auth::user()->verification && Auth::user()->verification->status !== 'verified' && Auth::user()->verification->status !== 'pending')),
                ],
            ]
        );

        return view('pages.stories.create', []);
    }

    /**
     * User for feed stories.
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function feed(Request $request)
    {
        if (!getSetting('stories.stories_enabled')) abort(404);

        $viewer = $request->user();
        $stories = StoriesServiceProvider::forFeed($viewer); // stays User $viewer
        $payload = StoriesServiceProvider::toFrontendPayload($stories);

        return response()->json($payload);
    }

    /**
     * Used for feed/individual user stories.
     * @param Request $request
     * @param string $username
     * @return \Illuminate\Http\JsonResponse
     */
    public function profile(Request $request, string $username)
    {
        if (!getSetting('stories.stories_enabled')) abort(404);

        $viewer = $request->user(); // can be null

        $owner = User::query()
            ->where('username', $username)
            ->firstOrFail();

        $stories = StoriesServiceProvider::forProfile($viewer, $owner); // provider must accept ?User
        $payload = StoriesServiceProvider::toFrontendPayload($stories);

        return response()->json($payload);
    }

    /**
     * Profile page highligts/pinned stories.
     * @param Request $request
     * @param string $username
     * @return \Illuminate\Http\JsonResponse
     */
    public function highlights(Request $request, string $username)
    {
        if (!getSetting('stories.stories_enabled')) abort(404);

        $viewer = $request->user(); // may be null

        $owner = User::query()
            ->where('username', $username)
            ->firstOrFail();

        $stories = StoriesServiceProvider::forHighlights($viewer, $owner);
        $payload = StoriesServiceProvider::toFrontendPayload($stories);

        return response()->json($payload);
    }

    /**
     * Messenger individual story on-demand.
     * @param $id
     * @return \Illuminate\Http\JsonResponse
     */
    public function payload($id)
    {
        $viewer = Auth::user();

        $story = Story::query()
            ->with([
                'user:id,name,username,avatar',
                'attachments' => function ($q) { $q->orderBy('created_at', 'asc'); },
                'sound.attachments',
            ])
            ->findOrFail((int)$id);

        if (!StoriesServiceProvider::canViewStory($viewer, $story)) {
            return response()->json(['success' => false, 'message' => __('Unauthorized')], 403);
        }

        $payload = StoriesServiceProvider::toFrontendPayload(collect([$story]));

        // payload is: { stories: [ bubble ] }
        return response()->json([
            'success' => true,
            'data' => $payload,
        ]);
    }

    /**
     * Saves the actual story.
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function store(Request $request)
    {
        if (!getSetting('stories.stories_enabled')) abort(404);
        $user = $request->user();

        $data = $request->validate([
            'mode'       => ['required', 'in:media,text'],
            'text'       => ['nullable', 'string', 'max:'.(getSetting('stories.max_text_length') ?: 2000)],
            'overlay_x' => ['nullable', 'numeric', 'min:0', 'max:1'],
            'overlay_y' => ['nullable', 'numeric', 'min:0', 'max:1'],
            'bg_preset'  => ['nullable', 'string', 'max:32'],
            'is_public'  => ['nullable', 'boolean'],
            'attachmentID' => ['nullable', 'string', 'exists:attachments,id'],
            'link_url'     => 'nullable|string|max:2048',
            'link_text'    => 'nullable|string|max:80',
            'sound_id' => ['nullable', 'integer', 'exists:sounds,id'],
        ]);

        // Normalize / safety
        $linkUrl = trim((string)($data['link_url'] ?? ''));
        if ($linkUrl !== '' && !preg_match('~^https?://~i', $linkUrl)) {
            return response()->json(['message' => __('Invalid link URL')], 422);
        }

        // If link_text provided without link_url -> ignore text
        $linkText = trim((string)($data['link_text'] ?? ''));
        if ($linkUrl === '') {
            $linkUrl = null;
            $linkText = null;
        }

        // If url exists but no label, set default
        if ($linkUrl && $linkText === '') {
            $linkText = __('Learn more');
        }

        // Mode guards
        if ($data['mode'] === 'media' && empty($data['attachmentID'])) {
            abort(422, __('Please upload a photo or video first.'));
        }
        if ($data['mode'] === 'text' && empty(trim((string)($data['text'] ?? '')))) {
            abort(422, __('Please write something first.'));
        }

        // Optional: enforce preset only for text mode
        if ($data['mode'] === 'text' && empty($data['bg_preset'])) {
            $data['bg_preset'] = 'solid_black';
        }

        $soundId = $data['sound_id'] ?? null;

        if ($soundId) {
            $isActive = Sound::where('id', $soundId)->where('is_active', 1)->exists();
            if (!$isActive) {
                return response()->json(['message' => __('Invalid sound.')], 422);
            }
        }

        $story = DB::transaction(function () use ($user, $data, $linkUrl, $linkText, $soundId) {

            $expiryHours = (int) getSetting('stories.story_expires_hours');
            if ($expiryHours <= 0) {
                $expiryHours = 24; // safe fallback
            }

            $story = Story::create([
                'user_id'     => $user->id,
                'expires_at'  => now()->addHours($expiryHours),
                'is_highlight'=> false,
                'is_public'   => !empty($data['is_public']) ? 1 : 0,

                'mode'        => $data['mode'],
                'text'        => $data['text'] ?? null,
                'overlay' => [
                    'x' => (float) ($data['overlay_x']),
                    'y' => (float) ($data['overlay_y']),
                ],
                'bg_preset'   => $data['mode'] === 'text' ? ($data['bg_preset'] ?? 'solid_black') : null,
                'link_url'   => $linkUrl,
                'link_text'  => $linkText,
                'sound_id' => $soundId,
            ]);

            // Link attachment only in media mode
            if ($data['mode'] === 'media') {
                $attachment = Attachment::query()
                    ->where('id', $data['attachmentID'])
                    ->where('user_id', $user->id)
                    ->lockForUpdate()
                    ->first();

                if (!$attachment) {
                    abort(422, __('Invalid attachment.'));
                }

                $attachment->story_id = $story->id;
                $attachment->save();
            }

            return $story;
        });

        return response()->json([
            'success' => true,
            'story_id' => $story->id,
            'redirect_url' => route('feed'),
        ]);
    }

    public function delete(Request $request)
    {
        if (!getSetting('stories.stories_enabled')) abort(404);
        $user = $request->user();

        $data = $request->validate([
            'story_id' => ['required', 'exists:stories,id'],
        ]);

        $story = Story::where('id', $data['story_id'])
            ->where('user_id', $user->id)
            ->first();

        if (!$story) {
            abort(403, __('Unauthorized.'));
        }

        DB::transaction(function () use ($story) {

            Attachment::where('story_id', $story->id)->update([
                'story_id' => null,
            ]);

            $story->delete();
        });

        return response()->json([
            'success' => true,
            'message' => __('Story deleted'),
        ]);
    }

    public function pinToggle(Request $request)
    {
        if (!(bool) getSetting('stories.allow_highlights')) {
            abort(403);
        }

        if (!getSetting('stories.stories_enabled')) abort(404);
        $user = $request->user();

        $data = $request->validate([
            'story_id' => ['required', 'exists:stories,id'],
        ]);

        $story = Story::where('id', $data['story_id'])
            ->where('user_id', $user->id)
            ->first();

        if (!$story) {
            abort(403, __('Unauthorized.'));
        }

        $story->is_highlight = !(bool) $story->is_highlight;
        $story->save();

        return response()->json([
            'success' => true,
            'pinned'  => (bool) $story->is_highlight,
            'message' => $story->is_highlight
                ? __('Story pinned')
                : __('Story unpinned'),
        ]);
    }

    public function share(Request $request, int $storyId)
    {
        if (!getSetting('stories.stories_enabled')) abort(404);

        $viewer = $request->user(); // may be null

        $story = Story::query()
            ->active()
            ->with('user:id,username')
            ->find($storyId);

        if (!$story) {
            abort(404);
        }

        // Guests: only public stories
        if (!$viewer) {
            if (!(bool) $story->is_public) {
                abort(404);
            }
        } else {
            // Logged in: normal access rules
            if (!StoriesServiceProvider::canViewStory($viewer, $story)) {
                abort(404); // you said you prefer 404
            }
        }

        // Redirect to owner's profile, keeping story id in query
        return redirect()->to(app()->make('url')->to('/'.$story->user->username).'?story='.(int) $storyId);
    }

    public function view(Request $request)
    {
        if (!getSetting('stories.stories_enabled')) abort(404);
        $viewer = Auth::user();

        $storyId = (int) $request->input('story_id');
        if (!$storyId) {
            return response()->json(['message' => __('Missing story_id')], 422);
        }

        // Find story (active only; adjust if your "active()" scope already exists)
        $story = Story::query()
            ->with('user:id')
            ->active()
            ->find($storyId);

        if (!$story) {
            return response()->json(['message' => __('Story not available')], 404);
        }

        // Access control (defense in depth)
        if (!StoriesServiceProvider::canViewStory($viewer, $story)) {
            return response()->json(['message' => __('Forbidden')], 403);
        }

        // Owner viewing their own story usually shouldn't count as a "view"
        $isOwner = ((int) $story->user_id === (int) $viewer->id);

        if (!$isOwner) {
            StoryView::updateOrCreate(
                [
                    'story_id' => (int) $story->id,
                    'user_id'  => (int) $viewer->id,
                ],
                [
                    'seen_at'  => now(),
                ]
            );
        }

        // Total views (unique viewers)
        $views = StoryView::query()
            ->where('story_id', (int) $story->id)
            ->count();

        return response()->json([
            'success' => true,
            'story_id' => (int) $story->id,
            'seen' => true,
            'views' => (int) $views,
            'owner' => $isOwner,
        ]);
    }
}
