<?php

namespace App\Http\Controllers\Api\Mobile;

use App\Http\Controllers\Controller;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Notifications\DatabaseNotification;

/**
 * Mobile-app notifications endpoints.
 *
 * Reads from Laravel's standard `notifications` table (Database channel).
 * Each notification's `data` JSON has: type, title, body, action_url, icon.
 *
 * Drives the Notifications screen: filter chips (All / Mentions / Mail /
 * Deals / Team), date-grouped sections (Today / Yesterday / older), unread
 * dot, mark-read, mark-all-read.
 */
class NotificationsController extends Controller
{
    /**
     * Notification-type → category mapping. The category drives the filter
     * chips and the icon style on each row. Anything not listed falls into
     * 'system' which only shows under "All".
     */
    private const TYPE_CATEGORIES = [
        // Mail
        'new_email'                 => 'mail',
        'email_received'            => 'mail',
        // Mentions (in notes / threads)
        'mention'                   => 'mentions',
        'note_mention'              => 'mentions',
        // Deals
        'deal_stage_changed'        => 'deals',
        'deal_won'                  => 'deals',
        'deal_lost'                 => 'deals',
        'deal_assigned'             => 'deals',
        // Team
        'team_member_joined'        => 'team',
        'team_member_left'          => 'team',
        'team_invitation'           => 'team',
        // System / other (only show under "All")
        'workflow_failed'           => 'system',
        'plan_limit_approaching'    => 'system',
        'trial_ending'              => 'system',
        'campaign_completed'        => 'system',
        'ai_escalation'             => 'system',
        'channel_connected'         => 'system',
        'backup_completed'          => 'system',
    ];

    /**
     * GET /api/v1/mobile/notifications
     *
     * Query params:
     *   - filter: all (default) | mentions | mail | deals | team
     *   - unread: 1 to limit to unread only
     *   - page: default 1
     *   - per_page: default 25, max 100
     */
    public function index(Request $request): JsonResponse
    {
        $user = $request->user();
        $perPage = (int) min(max((int) $request->query('per_page', 25), 5), 100);
        $filter  = (string) $request->query('filter', 'all');

        $query = $user->notifications()->latest();

        if ($request->boolean('unread')) {
            $query->whereNull('read_at');
        }

        // Filter by chip — translates to a list of allowed types
        $allowedTypes = $this->typesForFilter($filter);
        if ($allowedTypes !== null) {
            // Match against the `type` field inside the `data` JSON column.
            // We use whereIn on a JSON path because the row-level `type`
            // column is the Notification *class* name, not our app type key.
            $query->where(function ($q) use ($allowedTypes) {
                foreach ($allowedTypes as $t) {
                    $q->orWhereJsonContains('data->type', $t);
                }
            });
        }

        $page = $query->paginate($perPage);

        return response()->json([
            'data' => $page->getCollection()->map(fn (DatabaseNotification $n) => $this->shape($n))->all(),
            'meta' => [
                'current_page' => $page->currentPage(),
                'per_page'     => $page->perPage(),
                'total'        => $page->total(),
                'has_more'     => $page->hasMorePages(),
            ],
            'counts' => $this->categoryCounts($user),
            'unread_count' => (int) $user->unreadNotifications()->count(),
        ]);
    }

    /**
     * POST /api/v1/mobile/notifications/read-all
     * Mark every unread notification as read.
     */
    public function markAllRead(Request $request): JsonResponse
    {
        $request->user()->unreadNotifications->markAsRead();

        return response()->json([
            'message' => 'All notifications marked read.',
            'unread_count' => 0,
        ]);
    }

    /**
     * POST /api/v1/mobile/notifications/{id}/read
     * Mark a single notification as read.
     */
    public function markRead(Request $request, string $id): JsonResponse
    {
        $user = $request->user();
        $notification = $user->notifications()->where('id', $id)->first();

        if (!$notification) {
            return response()->json(['message' => 'Notification not found.'], 404);
        }

        $notification->markAsRead();

        return response()->json([
            'message' => 'Notification marked read.',
            'notification' => $this->shape($notification->fresh()),
            'unread_count' => (int) $user->unreadNotifications()->count(),
        ]);
    }

    /**
     * DELETE /api/v1/mobile/notifications/{id}
     * Dismiss (delete) a single notification.
     */
    public function destroy(Request $request, string $id): JsonResponse
    {
        $user = $request->user();
        $notification = $user->notifications()->where('id', $id)->first();

        if (!$notification) {
            return response()->json(['message' => 'Notification not found.'], 404);
        }

        $notification->delete();

        return response()->json([
            'message' => 'Notification dismissed.',
            'unread_count' => (int) $user->unreadNotifications()->count(),
        ]);
    }

    // ── Helpers ──────────────────────────────────────────────────────

    private function shape(DatabaseNotification $n): array
    {
        $data = is_array($n->data) ? $n->data : (json_decode((string) $n->data, true) ?: []);
        $type = (string) ($data['type'] ?? 'system');
        $category = self::TYPE_CATEGORIES[$type] ?? 'system';

        return [
            'id'              => $n->id,
            'type'            => $type,
            'category'        => $category,
            'title'           => (string) ($data['title'] ?? 'Notification'),
            'body'            => (string) ($data['body'] ?? ''),
            'action_url'      => $data['action_url'] ?? null,
            'icon'            => (string) ($data['icon'] ?? $this->iconFor($category)),
            'icon_color'      => (string) ($data['icon_color'] ?? $this->colorFor($category)),
            'avatar_url'      => $data['avatar_url'] ?? null,
            'avatar_initials' => $data['avatar_initials'] ?? null,
            'actions'         => $this->actionsFor($type, $data),
            'is_read'         => $n->read_at !== null,
            'read_at'         => $n->read_at?->toIso8601String(),
            'created_at'      => $n->created_at?->toIso8601String(),
            'created_human'   => $n->created_at?->diffForHumans(['short' => true]),
            'group'           => $this->groupFor($n->created_at),
        ];
    }

    /**
     * Build inline-action buttons for the notification card. Most types
     * have none; a few (AI escalation, channel-connected) get quick
     * buttons that the mobile app can render inline.
     */
    private function actionsFor(string $type, array $data): array
    {
        return match ($type) {
            'ai_escalation' => [
                ['key' => 'review',  'label' => 'Review',  'style' => 'primary',   'url' => $data['action_url'] ?? null],
                ['key' => 'dismiss', 'label' => 'Dismiss', 'style' => 'secondary', 'url' => null],
            ],
            'channel_connected' => isset($data['setup_url']) ? [
                ['key' => 'setup_auto_reply', 'label' => 'Set up auto-reply', 'style' => 'primary', 'url' => $data['setup_url']],
            ] : [],
            default => [],
        };
    }

    /**
     * Group label for date-section headers. Today, Yesterday, This week,
     * Earlier — matches the screenshot's TODAY / YESTERDAY sections.
     */
    private function groupFor(?\Carbon\Carbon $createdAt): string
    {
        if (!$createdAt) return 'earlier';
        $now = now();
        if ($createdAt->isSameDay($now))                      return 'today';
        if ($createdAt->isSameDay($now->copy()->subDay()))    return 'yesterday';
        if ($createdAt->gt($now->copy()->startOfWeek()))      return 'this_week';
        return 'earlier';
    }

    private function iconFor(string $category): string
    {
        return match ($category) {
            'mail'     => 'mail',
            'mentions' => 'at-sign',
            'deals'    => 'trending-up',
            'team'     => 'users',
            default    => 'bell',
        };
    }

    private function colorFor(string $category): string
    {
        return match ($category) {
            'mail'     => '#3b82f6', // blue
            'mentions' => '#8b5cf6', // purple
            'deals'    => '#ef4444', // red
            'team'     => '#22c55e', // green
            default    => '#6b7280', // gray
        };
    }

    /**
     * Category counts for the chip badges (the "8" on All in the screenshot).
     * "All" counts unread; per-category counts also count unread only — so
     * mobile can show a small badge on each chip.
     */
    private function categoryCounts($user): array
    {
        $counts = [
            'all'      => 0,
            'mentions' => 0,
            'mail'     => 0,
            'deals'    => 0,
            'team'     => 0,
        ];

        $unread = $user->unreadNotifications()->get(['id', 'data']);
        foreach ($unread as $n) {
            $data = is_array($n->data) ? $n->data : (json_decode((string) $n->data, true) ?: []);
            $type = (string) ($data['type'] ?? 'system');
            $cat  = self::TYPE_CATEGORIES[$type] ?? 'system';

            $counts['all']++;
            if (isset($counts[$cat])) {
                $counts[$cat]++;
            }
        }

        return $counts;
    }

    /**
     * Map a chip filter to a list of allowed type strings, or null for "all".
     */
    private function typesForFilter(string $filter): ?array
    {
        if ($filter === 'all' || $filter === '') return null;

        $byCategory = [];
        foreach (self::TYPE_CATEGORIES as $type => $cat) {
            $byCategory[$cat][] = $type;
        }

        return $byCategory[$filter] ?? [];
    }
}
