import path from 'path'
import { promises as fsp } from 'fs'
import { describe, it, expect } from 'vitest'
import * as ts from 'typescript'
import { parse as parseSfc } from '@vue/compiler-sfc'

// Recursively find all Vue files in a directory
async function findVueFiles(
  dir: string,
  ignorePatterns: string[] = [],
): Promise<string[]> {
  const entries = await fsp.readdir(dir, { withFileTypes: true })
  const files: string[] = []

  for (const entry of entries) {
    const fullPath = path.join(dir, entry.name)

    // Skip if path matches any ignore pattern
    if (ignorePatterns.some((pattern) => fullPath.includes(pattern))) {
      continue
    }

    if (entry.isDirectory()) {
      const subFiles = await findVueFiles(fullPath, ignorePatterns)
      files.push(...subFiles)
    } else if (entry.name.endsWith('.vue')) {
      files.push(fullPath)
    }
  }

  return files
}

// Parse a Vue SFC and check if the component's script calls the given function at least once.
function functionIsCalledAtLeastOnce(
  vueFileContents: string,
  functionName: string,
): boolean {
  const result = parseSfc(vueFileContents)
  const script = result.descriptor.scriptSetup?.content
  if (!script) {
    return false
  }
  const sourceFile = ts.createSourceFile(
    'temp.ts',
    script,
    ts.ScriptTarget.ES2015,
    true,
  )

  let isCalled = false

  function visit(node: ts.Node) {
    if (
      ts.isCallExpression(node) &&
      node.expression.getText(sourceFile) === functionName
    ) {
      isCalled = true
    }

    if (!isCalled) {
      ts.forEachChild(node, visit)
    }
  }

  ts.forEachChild(sourceFile, visit)

  return isCalled
}

describe('The Nuxt page component', async () => {
  const rootDir = path.resolve('app/pages')
  const ignorePatterns = ['blokkli']

  const pageFilePaths = await findVueFiles(rootDir, ignorePatterns)
  console.log(pageFilePaths)

  const pageComponentFiles = await Promise.all(
    pageFilePaths.map((filePath) => {
      return fsp.readFile(filePath, { encoding: 'utf8' }).then((content) => {
        return {
          filePath,
          content,
        }
      })
    }),
  )

  pageComponentFiles.forEach(({ filePath, content }) => {
    it(`"${filePath}" should call useDrupalRouteQuery()`, () => {
      expect(
        functionIsCalledAtLeastOnce(content, 'useDrupalRouteQuery'),
      ).toEqual(true)
    })
    it(`"${filePath}" should call renderPageDependencies()`, () => {
      expect(
        functionIsCalledAtLeastOnce(content, 'renderPageDependencies'),
      ).toEqual(true)
    })
  })
})
