import { getLayerDirectories } from '@nuxt/kit'
import { existsSync, lstatSync } from 'fs'
import { readFile } from 'fs/promises'
import { join } from 'path'
import { parse } from 'yaml'
import { fromInputJson, merge, type CanonicalValue } from './content-canonical'
import { type Plugin, build } from 'esbuild'

export function getLayerFiles(slug: string): string[] {
  return getLayerDirectories().flatMap((d) =>
    ['mts', 'yaml'].map((e) => join(d.app, `${slug}.${e}`))
  )
}

export async function getLayerContent(files: string[]): Promise<CanonicalValue | undefined> {
  const ts = await mergeTsFiles(
    files.filter((f) => f.endsWith('.mts') && existsSync(f) && lstatSync(f).isFile())
  )
  const yaml = await mergeYamlFiles(
    files.filter((f) => f.endsWith('.yaml') && existsSync(f) && lstatSync(f).isFile())
  )

  const merged = merge([ts, yaml].filter((c) => c !== undefined))
  return merged?.dropTags(['de', 'en', 'summer', 'winter']) // TODO
}

async function mergeTsFiles(files: string[]): Promise<CanonicalValue | undefined> {
  if (!files.length) return undefined

  try {
    const loader: Plugin = {
      name: 'file-loader',
      setup(build) {
        build.onLoad({ filter: /\.mts$/ }, async (args) => {
          let code = await readFile(args.path, 'utf-8')
          const index = files.indexOf(args.path)

          if (index < files.length - 1) {
            code = `
              export * from '${files[index + 1]}';
              import * as parent from '${files[index + 1]}';
              ${code}
            `
          }

          return { contents: code, loader: 'ts' }
        })
      },
    }

    const bundle = await build({
      entryPoints: [files[0]!],
      bundle: true,
      format: 'esm',
      platform: 'node',
      target: 'node22',
      write: false,
      sourcemap: 'inline',
      plugins: [loader],
    })

    const url =
      'data:text/javascript;base64,' + Buffer.from(bundle.outputFiles[0]!.text).toString('base64')

    const module = await import(url)
    return fromInputJson([], module.default)
  } catch (e) {
    const message = e instanceof Error ? e.message : String(e)
    console.error(`Unable to load merged ts: ${message}`)

    return undefined
  }
}

async function mergeYamlFiles(files: string[]): Promise<CanonicalValue | undefined> {
  const objects = await Promise.all(
    files.map(async (f) => {
      try {
        return fromInputJson([], parse(await readFile(f, 'utf-8')))
      } catch (e) {
        const message = e instanceof Error ? e.message : String(e)
        console.error(`Unable to load content file ${f}: ${message}`)

        return undefined
      }
    })
  )

  return merge(objects.filter((o) => !!o))
}
