<?php

declare(strict_types=1);

namespace App\Application\LiveComponents\NotificationCenter;

use App\Application\LiveComponents\LiveComponentState;

/**
 * Type-safe state for NotificationCenterComponent
 *
 * Provides compile-time type safety for notification center functionality.
 * All properties are readonly and immutable - transformations return new instances.
 */
final readonly class NotificationCenterState implements LiveComponentState
{
    public function __construct(
        public array $notifications = [],
        public int $unreadCount = 0,
        public string $filter = 'all',
        public bool $showPanel = false
    ) {
    }

    /**
     * Create from ComponentData (Framework → Domain conversion)
     */
    public static function fromArray(array $data): self
    {
        return new self(
            notifications: ($data['notifications'] ?? []),
            unreadCount: (int) ($data['unread_count'] ?? 0),
            filter: (string) ($data['filter'] ?? 'all'),
            showPanel: (bool) ($data['show_panel'] ?? false)
        );
    }

    /**
     * Create empty state with defaults
     */
    public static function empty(): self
    {
        return new self();
    }

    /**
     * Convert to ComponentData (Domain → Framework conversion)
     */
    public function toArray(): array
    {
        return [
            'notifications' => $this->notifications,
            'unread_count' => $this->unreadCount,
            'filter' => $this->filter,
            'show_panel' => $this->showPanel,
        ];
    }

    /**
     * Mark notification as read
     */
    public function withNotificationMarkedAsRead(string $notificationId): self
    {
        $notifications = $this->notifications;

        foreach ($notifications as &$notification) {
            if ($notification['id'] === $notificationId) {
                $notification['read'] = true;

                break;
            }
        }

        return new self(
            notifications: $notifications,
            unreadCount: $this->calculateUnreadCount($notifications),
            filter: $this->filter,
            showPanel: $this->showPanel
        );
    }

    /**
     * Mark notification as unread
     */
    public function withNotificationMarkedAsUnread(string $notificationId): self
    {
        $notifications = $this->notifications;

        foreach ($notifications as &$notification) {
            if ($notification['id'] === $notificationId) {
                $notification['read'] = false;

                break;
            }
        }

        return new self(
            notifications: $notifications,
            unreadCount: $this->calculateUnreadCount($notifications),
            filter: $this->filter,
            showPanel: $this->showPanel
        );
    }

    /**
     * Delete notification
     */
    public function withNotificationDeleted(string $notificationId): self
    {
        $notifications = array_filter(
            $this->notifications,
            fn ($notification) => $notification['id'] !== $notificationId
        );

        $notifications = array_values($notifications);

        return new self(
            notifications: $notifications,
            unreadCount: $this->calculateUnreadCount($notifications),
            filter: $this->filter,
            showPanel: $this->showPanel
        );
    }

    /**
     * Mark all notifications as read
     */
    public function withAllMarkedAsRead(): self
    {
        $notifications = array_map(function ($notification) {
            $notification['read'] = true;

            return $notification;
        }, $this->notifications);

        return new self(
            notifications: $notifications,
            unreadCount: 0,
            filter: $this->filter,
            showPanel: $this->showPanel
        );
    }

    /**
     * Delete all read notifications
     */
    public function withAllReadDeleted(): self
    {
        $notifications = array_filter(
            $this->notifications,
            fn ($notification) => ! $notification['read']
        );

        $notifications = array_values($notifications);

        return new self(
            notifications: $notifications,
            unreadCount: $this->calculateUnreadCount($notifications),
            filter: $this->filter,
            showPanel: $this->showPanel
        );
    }

    /**
     * Filter notifications by type
     */
    public function withFilter(string $filter): self
    {
        return new self(
            notifications: $this->notifications,
            unreadCount: $this->unreadCount,
            filter: $filter,
            showPanel: $this->showPanel
        );
    }

    /**
     * Toggle notification panel visibility
     */
    public function withToggledPanel(): self
    {
        return new self(
            notifications: $this->notifications,
            unreadCount: $this->unreadCount,
            filter: $this->filter,
            showPanel: ! $this->showPanel
        );
    }

    /**
     * Add new notification
     */
    public function withNotificationAdded(string $type, string $title, string $message): self
    {
        $notifications = $this->notifications;

        $newNotification = [
            'id' => uniqid('notif_', true),
            'type' => $type,
            'title' => $title,
            'message' => $message,
            'read' => false,
            'timestamp' => time(),
        ];

        array_unshift($notifications, $newNotification);
        $notifications = array_slice($notifications, 0, 50);

        return new self(
            notifications: $notifications,
            unreadCount: $this->calculateUnreadCount($notifications),
            filter: $this->filter,
            showPanel: true
        );
    }

    /**
     * Calculate unread count
     */
    private function calculateUnreadCount(array $notifications): int
    {
        return count(array_filter($notifications, fn ($n) => ! $n['read']));
    }

    /**
     * Get filtered notifications
     */
    public function getFilteredNotifications(): array
    {
        if ($this->filter === 'all') {
            return $this->notifications;
        }

        if ($this->filter === 'unread') {
            return array_filter($this->notifications, fn ($n) => ! $n['read']);
        }

        return array_filter(
            $this->notifications,
            fn ($n) => $n['type'] === $this->filter
        );
    }

    /**
     * Check if has unread notifications
     */
    public function hasUnreadNotifications(): bool
    {
        return $this->unreadCount > 0;
    }

    /**
     * Get notification by ID
     */
    public function getNotification(string $notificationId): ?array
    {
        foreach ($this->notifications as $notification) {
            if ($notification['id'] === $notificationId) {
                return $notification;
            }
        }

        return null;
    }

}
