import { describe, it, expect, vi, beforeEach } from 'vitest';
import { mount } from '@vue/test-utils';
import MSidebarFooter from './MSidebarFooter.vue';
import {
  TOGGLE_SIDEBAR_KEY,
  EXPANDED_SIDEBAR_KEY,
} from '../sidebar/MSidebar.const';
import { nextTick, ref } from 'vue';

const onTriggerKeydown = vi.fn();
const onListboxKeydown = vi.fn();
const hideFloatingItem = vi.fn();

vi.mock('../sidebar/use-floating-item.composable', () => {
  return {
    useFloatingItem: () => {
      const floatingItemIsDisplayed = ref(false);
      return {
        floatingItemIsDisplayed,
        showFloatingItem: () => (floatingItemIsDisplayed.value = true),
        hideFloatingItem: () => {
          floatingItemIsDisplayed.value = false;
          hideFloatingItem();
        },
        onTriggerKeydown,
        onListboxKeydown,
      };
    },
  };
});

vi.mock('../../utils/use-is-mobile.composable.ts', () => {
  return {
    useIsMobile: () => {
      return {
        isMobile: false,
      };
    },
  };
});

describe('MSidebarFooter', () => {
  const toggleSidebar = vi.fn();

  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('does not render profile when no img/title/subtitle provided', () => {
    const wrapper = mount(MSidebarFooter, {
      global: {
        provide: {
          [TOGGLE_SIDEBAR_KEY]: vi.fn(),
          [EXPANDED_SIDEBAR_KEY]: false,
        },
      },
    });

    expect(wrapper.find('.mc-sidebar__footer-profile').exists()).toBe(false);
    expect(wrapper.find('button').exists()).toBe(true);
  });

  it('renders img, title and subtitle when provided', () => {
    const props = {
      avatar: '/avatar.png',
      title: 'John Doe',
      subtitle: 'Designer',
      href: '/profile',
    };
    const wrapper = mount(MSidebarFooter, {
      props,
      global: {
        provide: {
          [TOGGLE_SIDEBAR_KEY]: vi.fn(),
          [EXPANDED_SIDEBAR_KEY]: true,
        },
      },
    });

    const profile = wrapper.find('.mc-sidebar__footer-profile');
    expect(profile.exists()).toBe(true);

    const img = wrapper.find('.mc-sidebar__footer-avatar');
    expect(img.exists()).toBe(true);
    expect(img.attributes('src')).toBe('/avatar.png');
    expect(img.attributes('alt')).toBe('John Doe');

    expect(wrapper.find('.mc-sidebar__footer-title').text()).toBe('John Doe');
    expect(wrapper.find('.mc-sidebar__footer-subtitle').text()).toBe(
      'Designer',
    );
  });

  it('hides expand button when expandable prop is false', () => {
    const wrapper = mount(MSidebarFooter, {
      props: { expendable: false },
      global: {
        provide: {
          [TOGGLE_SIDEBAR_KEY]: vi.fn(),
          [EXPANDED_SIDEBAR_KEY]: false,
        },
      },
    });

    expect(wrapper.find('.mc-sidebar__footer-expand').exists()).toBe(false);
  });

  it('binds aria-expanded and calls toggle function when clicked', async () => {
    const toggle = vi.fn();
    const wrapper = mount(MSidebarFooter, {
      global: {
        provide: {
          [TOGGLE_SIDEBAR_KEY]: toggle,
          [EXPANDED_SIDEBAR_KEY]: true,
        },
      },
    });

    const button = wrapper.find('button');
    expect(button.attributes('aria-expanded')).toBe('true');

    await button.trigger('click');
    expect(toggle).toHaveBeenCalled();
  });

  it('emits "log-out" when log out button is clicked', async () => {
    const wrapper = mount(MSidebarFooter, {
      props: {
        title: 'John Doe',
        logOutLabel: 'Log out',
      },
      global: {
        provide: {
          [EXPANDED_SIDEBAR_KEY]: true,
          [TOGGLE_SIDEBAR_KEY]: vi.fn(),
        },
        stubs: {
          MDivider: true,
          MButton: true,
          MSidebarNavItem: {
            template: `
              <div data-test="logout" @click="$emit('click')">
                Log out
              </div>
            `,
          },
        },
      },
    });

    const logoutItem = wrapper.find('[data-test="logout"]');

    expect(logoutItem.exists()).toBe(true);

    await logoutItem.trigger('click');

    expect(wrapper.emitted('log-out')).toBeTruthy();
  });

  it('shows floating item on mouseenter when collapsed', async () => {
    const wrapper = mount(MSidebarFooter, {
      props: { title: 'John Doe' },
      global: {
        provide: {
          [EXPANDED_SIDEBAR_KEY]: false,
          [TOGGLE_SIDEBAR_KEY]: toggleSidebar,
        },
      },
    });

    const trigger = wrapper.find('button.mc-sidebar__footer-trigger');
    expect(trigger.exists()).toBe(true);
    expect(trigger.attributes('aria-expanded')).toBe('false');

    await trigger.trigger('mouseenter');
    await nextTick();

    expect(trigger.attributes('aria-expanded')).toBe('true');
  });

  it('hides floating item on mouseleave and blur when collapsed', async () => {
    const wrapper = mount(MSidebarFooter, {
      props: { title: 'John Doe' },
      global: {
        provide: {
          [EXPANDED_SIDEBAR_KEY]: false,
          [TOGGLE_SIDEBAR_KEY]: toggleSidebar,
        },
      },
    });

    const trigger = wrapper.find('button.mc-sidebar__footer-trigger');

    await trigger.trigger('mouseenter');
    await nextTick();

    await trigger.trigger('mouseleave');
    expect(hideFloatingItem).toHaveBeenCalledTimes(1);

    await trigger.trigger('blur');
    expect(hideFloatingItem).toHaveBeenCalledTimes(2);
  });

  it('calls onTriggerKeydown on keydown when collapsed', async () => {
    const wrapper = mount(MSidebarFooter, {
      props: { title: 'John Doe' },
      global: {
        provide: {
          [EXPANDED_SIDEBAR_KEY]: false,
          [TOGGLE_SIDEBAR_KEY]: toggleSidebar,
        },
      },
    });

    const trigger = wrapper.find('button.mc-sidebar__footer-trigger');

    await trigger.trigger('keydown', { key: 'ArrowDown' });
    expect(onTriggerKeydown).toHaveBeenCalled();
  });

  it('calls onListboxKeydown when keydown is emitted on the listbox', async () => {
    const wrapper = mount(MSidebarFooter, {
      props: { title: 'John Doe' },
      global: {
        provide: {
          [EXPANDED_SIDEBAR_KEY]: false,
          [TOGGLE_SIDEBAR_KEY]: toggleSidebar,
        },
      },
    });

    const listbox = wrapper.find('#listbox-footer');
    expect(listbox.exists()).toBe(true);

    await listbox.trigger('keydown');
    expect(onListboxKeydown).toHaveBeenCalled();
  });

  it('calls hideFloatingItem on mouseleave and blur on the listbox', async () => {
    const wrapper = mount(MSidebarFooter, {
      props: { title: 'John Doe' },
      global: {
        provide: {
          [EXPANDED_SIDEBAR_KEY]: false,
          [TOGGLE_SIDEBAR_KEY]: toggleSidebar,
        },
      },
    });

    const listbox = wrapper.find('#listbox-footer');

    await listbox.trigger('mouseleave');
    expect(hideFloatingItem).toHaveBeenCalledTimes(1);

    await listbox.trigger('blur');
    expect(hideFloatingItem).toHaveBeenCalledTimes(2);
  });

  it('calls toggleSidebar when expand button is clicked', async () => {
    const wrapper = mount(MSidebarFooter, {
      props: { title: 'John Doe' },
      global: {
        provide: {
          [EXPANDED_SIDEBAR_KEY]: false,
          [TOGGLE_SIDEBAR_KEY]: toggleSidebar,
        },
      },
    });

    const expandButton = wrapper.find('.mc-sidebar__footer-expand');
    expect(expandButton.exists()).toBe(true);

    await expandButton.trigger('click');
    expect(toggleSidebar).toHaveBeenCalledTimes(1);
  });
});
