import { mount } from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing';
import { useNotificationStore, type Notification } from '@/stores/notifications';
import NotificationDisplay from '@/components/global/NotificationDisplay.vue';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { nextTick } from 'vue';

// Helper to generate unique IDs for test notifications
let idCounter = 0;
const generateTestId = () => `test_notif_${idCounter++}`;

describe('NotificationDisplay.vue', () => {
  beforeEach(() => {
    // Reset idCounter for consistent IDs across tests
    idCounter = 0;
  });

  it('renders correctly when there are no notifications', () => {
    const pinia = createTestingPinia({
      initialState: {
        notifications: { notifications: [] },
      },
      stubActions: false, // We want to spy on actions
    });

    const wrapper = mount(NotificationDisplay, {
      global: {
        plugins: [pinia],
      },
    });

    expect(wrapper.find('.notification-container').exists()).toBe(true);
    expect(wrapper.findAll('.alert').length).toBe(0);
  });

  it('displays a single notification with correct message and type', async () => {
    const testNotification: Notification = {
      id: generateTestId(),
      message: 'Test Success!',
      type: 'success',
    };
    const pinia = createTestingPinia({
      initialState: {
        notifications: { notifications: [testNotification] },
      },
      stubActions: false,
    });

    const wrapper = mount(NotificationDisplay, {
      global: {
        plugins: [pinia],
      },
    });

    await nextTick(); // Wait for reactivity

    const notificationElements = wrapper.findAll('.alert');
    expect(notificationElements.length).toBe(1);
    const notificationElement = notificationElements[0];
    expect(notificationElement.text()).toContain('Test Success!');
    expect(notificationElement.classes()).toContain('alert-success');
    // Check for success icon (specific path data might be too brittle, check for presence of svg)
    expect(notificationElement.find('svg[fill="currentColor"]').exists()).toBe(true);
  });

  it('displays multiple notifications', async () => {
    const notificationsList: Notification[] = [
      { id: generateTestId(), message: 'Error occurred', type: 'error' },
      { id: generateTestId(), message: 'Info message', type: 'info' },
    ];
    const pinia = createTestingPinia({
      initialState: {
        notifications: { notifications: notificationsList },
      },
      stubActions: false,
    });

    const wrapper = mount(NotificationDisplay, {
      global: {
        plugins: [pinia],
      },
    });
    await nextTick();

    const notificationElements = wrapper.findAll('.alert');
    expect(notificationElements.length).toBe(2);
    expect(notificationElements[0].text()).toContain('Error occurred');
    expect(notificationElements[0].classes()).toContain('alert-error');
    expect(notificationElements[1].text()).toContain('Info message');
    expect(notificationElements[1].classes()).toContain('alert-info');
  });

  it('calls store.removeNotification when a notification close button is clicked', async () => {
    const notifIdToRemove = generateTestId();
    const initialNotifications: Notification[] = [
      { id: notifIdToRemove, message: 'Dismiss me', type: 'warning' },
      { id: generateTestId(), message: 'Keep me', type: 'info' },
    ];

    const pinia = createTestingPinia({
      initialState: {
        notifications: { notifications: [...initialNotifications] },
      },
      stubActions: false, // So we can spy on the actual action
      plugins: [
        ({ store }) => {
          if (store.$id === 'notifications') {
            // Spy on the actual action if not stubbed
            // @ts-ignore
            store.removeNotification = vi.fn(store.removeNotification);
          }
        }
      ]
    });
    
    const notificationStore = useNotificationStore(pinia);

    const wrapper = mount(NotificationDisplay, {
      global: {
        plugins: [pinia],
      },
    });
    await nextTick();

    const notificationElements = wrapper.findAll('.alert');
    expect(notificationElements.length).toBe(2);

    const firstNotificationCloseButton = notificationElements[0].find('.alert-close-btn');
    expect(firstNotificationCloseButton.exists()).toBe(true);
    await firstNotificationCloseButton.trigger('click');

    expect(notificationStore.removeNotification).toHaveBeenCalledTimes(1);
    expect(notificationStore.removeNotification).toHaveBeenCalledWith(notifIdToRemove);

    // Simulate store removing the notification
    // In a real scenario, the action would modify the state.
    // Here we check the spy, and can also manually update state for UI check.
    // @ts-ignore
    notificationStore.notifications = initialNotifications.filter(n => n.id !== notifIdToRemove);
    await nextTick();

    expect(wrapper.findAll('.alert').length).toBe(1);
    expect(wrapper.text()).not.toContain('Dismiss me');
    expect(wrapper.text()).toContain('Keep me');
  });

  it('renders correct icons for different notification types', async () => {
    const notificationsList: Notification[] = [
      { id: generateTestId(), message: 'Success', type: 'success' },
      { id: generateTestId(), message: 'Error', type: 'error' },
      { id: generateTestId(), message: 'Warning', type: 'warning' },
      { id: generateTestId(), message: 'Info', type: 'info' },
    ];
    const pinia = createTestingPinia({
      initialState: {
        notifications: { notifications: notificationsList },
      },
      stubActions: false,
    });

    const wrapper = mount(NotificationDisplay, {
      global: {
        plugins: [pinia],
      },
    });
    await nextTick();

    const alerts = wrapper.findAll('.alert');
    expect(alerts[0].find('svg[viewBox="0 0 24 24"]').exists()).toBe(true); // Basic check for any SVG
    expect(alerts[0].classes()).toContain('alert-success');

    expect(alerts[1].find('svg[viewBox="0 0 24 24"]').exists()).toBe(true);
    expect(alerts[1].classes()).toContain('alert-error');

    expect(alerts[2].find('svg[viewBox="0 0 24 24"]').exists()).toBe(true);
    expect(alerts[2].classes()).toContain('alert-warning');

    expect(alerts[3].find('svg[viewBox="0 0 24 24"]').exists()).toBe(true);
    expect(alerts[3].classes()).toContain('alert-info');
  });
});
