import { describe, expect, test, vi } from 'vitest'
import type { Meta, StoryFn } from '@storybook/vue3'
import { render } from '@testing-library/vue'
import { composeStories } from '@storybook/vue3'
import { h } from 'vue'
import { sleep } from 'camino-common/src/typescript-tools'

type StoryFile = {
  default: Meta
  [name: string]: StoryFn | Meta
}
console.error = vi.fn()
vi.mock('./../demarche/demarche-map.tsx', () => ({
  DemarcheMap: (props: any) => h('mocked-map', props, [Object.keys(props).map(key => h(key, {}, JSON.stringify(props[key])))]),
}))
vi.mock('vue-router', () => ({
  useRoute: vi.fn(() => ({
    name: 'mocked-current-route',
    query: {},
  })),
  onBeforeRouteLeave: vi.fn(),
  useLink: () => ({ href: { value: '/mocked-href' } }),
  useRouter: vi.fn(() => ({
    push: vi.fn(),
    currentRoute: { value: { name: 'mocked-current-route', query: {} } },
  })),
}))

const compose = (entry: StoryFile): ReturnType<typeof composeStories<StoryFile>> => {
  try {
    return composeStories(entry)
  } catch (e) {
    throw new Error(`Un fichier est probablement mal formaté ${JSON.stringify(entry)}, ${e}`)
  }
}
describe('Common Storybook Tests', async () => {
  const modules = Object.entries(import.meta.glob<StoryFile>(['./**/*.stories.ts(x)?'], { eager: true })).map(([filePath, storyFile]) => ({ filePath, storyFile }))
  describe.each(
    modules.map(({ filePath, storyFile }) => {
      return { name: storyFile.default.title, storyFile, filePath }
    })
  )('$name', ({ name, storyFile, filePath }) => {
    test.skipIf(name?.includes('NoStoryshots')).each(
      Object.entries(compose(storyFile))
        .map(([name, story]) => ({ name, story }))
        .filter(env => (name ?? '').includes('NoStoryshots') || !(env.name ?? '').includes('NoSnapshot'))
    )('$name', async value => {
      let html: string | undefined = undefined
      try {
        // @ts-ignore
        window.dsfr = null

        class ResizeObserver {
          observe() {
            // do nothing
          }

          unobserve() {
            // do nothing
          }

          disconnect() {
            // do nothing
          }
        }

        global.ResizeObserver = ResizeObserver

        const storyComponent = value.story()

        const mounted = render('type' in storyComponent && typeof storyComponent.type === 'function' ? storyComponent.type() : storyComponent, {
          global: {
            components: { 'router-link': (props, { slots }) => h('a', { ...props, type: 'primary', to: JSON.stringify(props.to).replaceAll('"', '') }, slots) },
          },
        })

        await sleep(1)
        html = mounted.html()
      } catch (e) {
        throw new Error(`le test ${name} du fichier ${filePath} plante ${e}`)
      } finally {
        if (html === undefined) {
          throw new Error('le test ne génère pas de html')
        }
        await expect(html).toMatchFileSnapshot(`./${filePath.replace(/\.[^/.]+$/, '')}_snapshots_${value.name}.html`)
      }
    })
  })
})
