<?php

namespace App\Http\Controllers;

use App\Models\Activity;
use App\Models\Company;
use App\Models\Contact;
use App\Models\Deal;
use App\Models\Task;
use App\Models\User;
use App\Models\WebForm;
use App\Models\WebFormSubmission;
use App\Support\RightRailManager;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

class NotificationController extends Controller
{
    public function feed(Request $request, RightRailManager $rightRailManager): JsonResponse
    {
        /** @var User $user */
        $user = $request->user();
        $data = $rightRailManager->data($user);
        $notifications = collect($data['notifications'] ?? [])
            ->values()
            ->map(function (array $item): array {
                $key = (string) ($item['key'] ?? '');
                $item['open_url'] = $key !== ''
                    ? route('notifications.open', ['key' => $key])
                    : route('dashboard');

                return $item;
            });

        return response()->json([
            'notifications' => $notifications->all(),
            'unread_count' => (int) $notifications->count(),
        ]);
    }

    public function open(Request $request, string $key): RedirectResponse
    {
        /** @var User $user */
        $user = $request->user();

        $normalizedKey = $this->normalizeKey($key);
        $destination = $normalizedKey !== null
            ? $this->resolveDestination($user, $normalizedKey)
            : null;

        if ($normalizedKey !== null) {
            $this->markViewed($user, $normalizedKey);
        }

        return redirect()->to($destination ?? route('dashboard'));
    }

    private function resolveDestination(User $user, string $key): ?string
    {
        if (preg_match('/^form-submission-(\d+)(?:-[A-Za-z0-9:_-]+)?$/', $key, $matches)) {
            $submissionId = (int) ($matches[1] ?? 0);
            if ($submissionId <= 0) {
                return null;
            }

            return $this->formSubmissionUrl($user, $submissionId);
        }

        if (! preg_match('/^(task|deal|activity)-(\d+)(?:-[A-Za-z0-9:_-]+)?$/', $key, $matches)) {
            return null;
        }

        $type = (string) ($matches[1] ?? '');
        $id = (int) ($matches[2] ?? 0);

        if ($id <= 0) {
            return null;
        }

        return match ($type) {
            'task' => $this->taskUrl($user, $id),
            'deal' => $this->dealUrl($user, $id),
            'activity' => $this->activityUrl($user, $id),
            default => null,
        };
    }

    private function formSubmissionUrl(User $user, int $submissionId): ?string
    {
        $submission = WebFormSubmission::query()
            ->with('form:id,owner_id')
            ->find($submissionId);

        $form = $submission?->form;
        if (! $submission || ! $form || (int) $form->owner_id !== (int) $user->id) {
            return null;
        }

        $resultType = (string) $submission->result_type;
        $resultId = (int) ($submission->result_id ?? 0);

        if ($resultId > 0) {
            if ($resultType === 'task') {
                $destination = $this->taskUrl($user, $resultId);
                if ($destination !== null) {
                    return $destination;
                }
            }

            if ($resultType === 'deal') {
                $destination = $this->dealUrl($user, $resultId);
                if ($destination !== null) {
                    return $destination;
                }
            }

            if ($resultType === 'activity') {
                $destination = $this->activityUrl($user, $resultId);
                if ($destination !== null) {
                    return $destination;
                }
            }

            if ($resultType === 'company') {
                $company = Company::query()->find($resultId);
                if ($company && $user->can('view', $company)) {
                    return route('companies.show', $company);
                }
            }

            if ($resultType === 'contact') {
                $contact = Contact::query()->find($resultId);
                if ($contact && $user->can('view', $contact)) {
                    return route('contacts.show', $contact);
                }
            }
        }

        if ($user->can('update', $form)) {
            return route('forms.edit', $form);
        }

        if ($user->can('viewAny', WebForm::class)) {
            return route('forms.index');
        }

        return null;
    }

    private function taskUrl(User $user, int $taskId): ?string
    {
        $task = Task::query()->find($taskId);
        if (! $task || $user->cannot('view', $task)) {
            return null;
        }

        return route('tasks.show', $task);
    }

    private function dealUrl(User $user, int $dealId): ?string
    {
        $deal = Deal::query()->find($dealId);
        if (! $deal || $user->cannot('view', $deal)) {
            return null;
        }

        return route('deals.show', $deal);
    }

    private function activityUrl(User $user, int $activityId): ?string
    {
        $activity = Activity::query()
            ->with('deal:id,title')
            ->find($activityId);

        if (! $activity || $user->cannot('view', $activity)) {
            return null;
        }

        if ($activity->deal) {
            return route('deals.show', $activity->deal);
        }

        return route('activities.show', $activity);
    }

    private function normalizeKey(string $key): ?string
    {
        $key = trim($key);
        if ($key === '') {
            return null;
        }

        if (! preg_match('/^(task|deal|activity)-\d+(?:-[A-Za-z0-9:_-]+)?$|^form-submission-\d+(?:-[A-Za-z0-9:_-]+)?$/', $key)) {
            return null;
        }

        return $key;
    }

    private function markViewed(User $user, string $key): void
    {
        $viewed = collect($user->right_rail_viewed_notifications ?? [])
            ->filter(fn (mixed $value): bool => is_string($value) && $value !== '')
            ->push($key)
            ->unique()
            ->values();

        if ($viewed->count() > 500) {
            $viewed = $viewed->slice($viewed->count() - 500)->values();
        }

        $user->forceFill([
            'right_rail_viewed_notifications' => $viewed->all(),
        ])->save();
    }
}
