import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { mount } from '@vue/test-utils'
import { createRouter, createMemoryHistory } from 'vue-router'
import MainLayout from '../MainLayout.vue'

Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: (query: string) => ({
    matches: false, media: query, onchange: null,
    addListener: () => {}, removeListener: () => {},
    addEventListener: () => {}, removeEventListener: () => {},
    dispatchEvent: () => false,
  }),
})

function createTestRouter() {
  return createRouter({
    history: createMemoryHistory(),
    routes: [
      { path: '/', component: { template: '<div>Home</div>' } },
      { path: '/users', component: { template: '<div>Users</div>' } },
      { path: '/orders', component: { template: '<div>Orders</div>' } },
      { path: '/login', component: { template: '<div>Login</div>' } },
      { path: '/profile', component: { template: '<div>Profile</div>' } },
      { path: '/profile/password', component: { template: '<div>Password</div>' } },
    ],
  })
}

describe('MainLayout', () => {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  let wrapper: any

  beforeEach(() => {
    vi.restoreAllMocks()
    document.body.innerHTML = ''
    setActivePinia(createPinia())
    localStorage.clear()
  })

  afterEach(() => {
    wrapper?.unmount()
    wrapper = undefined
    document.body.innerHTML = ''
  })

  async function mountLayout(route = '/') {
    const router = createTestRouter()
    await router.push(route)
    await router.isReady()

    const w = mount(MainLayout, {
      global: {
        plugins: [router],
        stubs: {
          // Stub icons to avoid import issues in test
          MenuFoldOutlined: { template: '<span class="fold-icon" />' },
          MenuUnfoldOutlined: { template: '<span class="unfold-icon" />' },
          DashboardOutlined: { template: '<span />' },
          UserOutlined: { template: '<span />' },
          ShoppingOutlined: { template: '<span />' },
          FileTextOutlined: { template: '<span />' },
          UnorderedListOutlined: { template: '<span />' },
          DollarOutlined: { template: '<span />' },
          MonitorOutlined: { template: '<span />' },
          LogoutOutlined: { template: '<span />' },
          SettingOutlined: { template: '<span />' },
          KeyOutlined: { template: '<span />' },
          // Stub dropdown to render overlay inline (avoids Teleport in jsdom)
          ADropdown: { template: '<div><slot /><slot name="overlay" /></div>' },
          Brand: { template: '<div class="brand-stub" />' },
        },
      },
      slots: {
        default: '<div class="test-content">Page Content</div>',
      },
    })
    wrapper = w
    return w
  }

  it('renders all four layout areas', async () => {
    const wrapper = await mountLayout()

    expect(wrapper.find('.ant-layout-header').exists()).toBe(true)
    expect(wrapper.find('.ant-layout-sider').exists()).toBe(true)
    expect(wrapper.find('.ant-layout-content').exists()).toBe(true)
    expect(wrapper.find('.ant-layout-footer').exists()).toBe(true)
  })

  it('renders slot content in content area', async () => {
    const wrapper = await mountLayout()

    expect(wrapper.find('.test-content').text()).toBe('Page Content')
  })

  it('renders footer copyright', async () => {
    const wrapper = await mountLayout()

    expect(wrapper.find('.ant-layout-footer').text()).toContain('2026 DataHub')
  })

  it('toggles sidebar collapse state', async () => {
    const wrapper = await mountLayout()
    const sider = wrapper.findComponent({ name: 'ALayoutSider' })

    expect(sider.props('collapsed')).toBe(false)

    // Click the fold icon to collapse
    await wrapper.find('.fold-icon').trigger('click')
    expect(sider.props('collapsed')).toBe(true)
    expect(localStorage.getItem('sidebarCollapsed')).toBe('true')

    // Click the unfold icon to expand
    await wrapper.find('.unfold-icon').trigger('click')
    expect(sider.props('collapsed')).toBe(false)
    expect(localStorage.getItem('sidebarCollapsed')).toBe('false')
  })

  it('restores collapsed state from localStorage', async () => {
    localStorage.setItem('sidebarCollapsed', 'true')
    const wrapper = await mountLayout()
    const sider = wrapper.findComponent({ name: 'ALayoutSider' })

    expect(sider.props('collapsed')).toBe(true)
  })

  it('displays username from localStorage', async () => {
    localStorage.setItem('user', JSON.stringify({ username: 'testuser' }))
    const wrapper = await mountLayout()

    expect(wrapper.find('.ant-layout-header').text()).toContain('testuser')
  })

  it('displays default username when no user in localStorage', async () => {
    const wrapper = await mountLayout()

    expect(wrapper.find('.ant-layout-header').text()).toContain('admin')
  })

  it('renders navigation menu items', async () => {
    const wrapper = await mountLayout()
    const menuItems = wrapper.findAll('.ant-menu-item, .ant-menu-submenu')

    expect(menuItems.length).toBeGreaterThan(0)
  })

  it('renders breadcrumb with home on root path', async () => {
    const wrapper = await mountLayout('/')
    const breadcrumb = wrapper.find('.ant-breadcrumb')

    expect(breadcrumb.exists()).toBe(true)
    expect(breadcrumb.text()).toContain('首页')
  })

  it('navigates to /profile when clicking profile menu item', async () => {
    const wrapper = await mountLayout()
    const vm = wrapper.getCurrentComponent()
    const router = vm.appContext.config.globalProperties.$router
    const pushSpy = vi.spyOn(router, 'push')

    // ADropdown is stubbed to render overlay inline, so menu items are in the wrapper
    const menuItems = wrapper.findAll('.ant-menu-item')
    const profileItem = menuItems.find((item) => item.text().includes('个人信息'))
    expect(profileItem).toBeTruthy()
    await profileItem!.trigger('click')
    expect(pushSpy).toHaveBeenCalledWith('/profile')
  })

  it('navigates to /profile/password when clicking password menu item', async () => {
    const wrapper = await mountLayout()
    const vm = wrapper.getCurrentComponent()
    const router = vm.appContext.config.globalProperties.$router
    const pushSpy = vi.spyOn(router, 'push')

    const menuItems = wrapper.findAll('.ant-menu-item')
    const passwordItem = menuItems.find((item) => item.text().includes('修改密码'))
    expect(passwordItem).toBeTruthy()
    await passwordItem!.trigger('click')
    expect(pushSpy).toHaveBeenCalledWith('/profile/password')
  })

  it('renders profile breadcrumb on /profile path', async () => {
    const wrapper = await mountLayout('/profile')
    const breadcrumb = wrapper.find('.ant-breadcrumb')

    expect(breadcrumb.text()).toContain('个人信息')
  })

  it('renders password breadcrumb on /profile/password path', async () => {
    const wrapper = await mountLayout('/profile/password')
    const breadcrumb = wrapper.find('.ant-breadcrumb')

    expect(breadcrumb.text()).toContain('修改密码')
  })
})
