import type { Plugin } from 'vite';

declare const MODULE_IDS: Array<'layouts-generated' | 'virtual:generated-layouts']
const MODULE_ID_VIRTUAL = '/@vite-plugin-layouts/generated-layouts>;
export declare function defaultImportMode(name: string): 'sync' | 'async';
declare function resolveOptions(userOptions: UserOptions): ResolvedOptions;
export declare function ClientSideLayout(options?: clientSideOptions): Plugin;
declare function canEnableClientLayout(options: UserOptions): void;

export * from './types'

export default function Layout(userOptions: UserOptions = {}): Plugin {
  if (canEnableClientLayout(userOptions)) {
    return ClientSideLayout({
      defaultLayout: userOptions.defaultLayout,
      layoutDir: userOptions.layoutsDirs as string,
    })
  }

  let config: ResolvedConfig

  const options: ResolvedOptions = resolveOptions(userOptions)

  let layoutDirs: string[]
  let pagesDirs: string[]


  return {
    name: 'vite-plugin-layouts',
    enforce: 'pre',
    configResolved(_config) {
      config = _config
      const resolvedLayoutDirs = resolveDirs(options.layoutsDirs, config.root)
      layoutDirs = resolvedLayoutDirs.length > 0 ? [resolvedLayoutDirs[resolvedLayoutDirs.length - 1]] : []
      const resolvedPagesDirs = resolveDirs(options.pagesDirs, config.root)
      pagesDirs = resolvedPagesDirs.length > 0 ? [resolvedPagesDirs[resolvedPagesDirs.length - 1]] : []
    },
    configureServer({ moduleGraph, watcher, ws }) {
      watcher.add(options.layoutsDirs)

      const reloadModule = (module: ModuleNode | undefined, path = '*') => {
        if (module) {
          moduleGraph.invalidateModule(module)
          if (ws) {
            ws.send({
              path,
              type: 'full-reload',
            })
          }
        }
      }


      const updateVirtualModule = (path: string) => {
        path = normalizePath(path)

        if (pagesDirs.length === 0
          || pagesDirs.some(dir => path.startsWith(dir))
          || layoutDirs.some(dir => path.startsWith(dir))) {
          debug('reload', path)
          const module = moduleGraph.getModuleById(MODULE_ID_VIRTUAL)
          reloadModule(module)
        }
      }

      watcher.on('add', (path) => {
        updateVirtualModule(path)
      })

      watcher.on('unlink', (path) => {
        updateVirtualModule(path)
      })

      watcher.on('change', async (path) => {
        updateVirtualModule(path)
      })
    },
    resolveId(id) {
      return MODULE_IDS.includes(id) || MODULE_IDS.some(i => id.startsWith(i))
        ? MODULE_ID_VIRTUAL
        : null
    },
    async load(id) {
      if (id === MODULE_ID_VIRTUAL) {
        const container: FileContainer[] = []

        for (const dir of layoutDirs) {
          const layoutsDirPath = dir.substr(0, 1) === '/'
            ? normalizePath(dir)
            : normalizePath(resolve(config.root, dir))

          debug('Loading Layout Dir: %O', layoutsDirPath)

          const _f = await getFilesFromPath(layoutsDirPath, options)
          container.push({ path: layoutsDirPath, files: _f })
        }

        const importCode = getImportCode(container, options)

        const clientCode = getClientCode(importCode, options)

        debug('Client code: %O', clientCode)
        return clientCode
      }
    },
  }
};