import { useBambooContext } from '@/src/hooks/useBambooContext'
import { State } from '@/src/hooks/usePlayground'
import { Project } from '@bamboocss/parser'
import type { Config } from '@bamboocss/types'
import { useMemo } from 'react'
import { useDebounceValue } from 'usehooks-ts'

export function useBamboo(state: State, config: Config | null) {
  const [source] = useDebounceValue(state.code, 150)
  const [css] = useDebounceValue(state.css, 150)

  const context = useBambooContext(config)

  const staticArtifacts = useMemo(() => {
    const sheet = context.createSheet()
    context.appendLayerParams(sheet)
    context.appendBaselineCss(sheet)

    const staticSheet = context.createSheet()
    context.appendCssOfType('static', staticSheet)

    const cssArtifacts = [
      { file: 'Tokens', code: sheet.getLayerCss('tokens') },
      { file: 'Reset', code: sheet.getLayerCss('reset') },
      { file: 'Global', code: sheet.getLayerCss('base') },
      { file: 'Static', code: staticSheet.getLayerCss('recipes', 'utilities') },
    ]

    return cssArtifacts
  }, [context])

  // Artifacts only depend on config (context), not source code
  const { artifacts, previewJs } = useMemo(() => {
    const artifacts = context.getArtifacts() ?? []
    const allJsFiles = artifacts.flatMap((a) => a?.files.filter((f) => f.file.endsWith('.mjs')) ?? [])
    const previewJs = allJsFiles
      .map((f) => f.code?.replaceAll(/import .*/g, '').replaceAll(/export \* from '(.+?)';/g, ''))
      ?.join('\n')
    return { artifacts, previewJs }
  }, [context])

  return useMemo(() => {
    const project = new Project({
      useInMemoryFileSystem: true,
      parserOptions: context.parserOptions,
      getFiles: () => ['code.tsx'],
      readFile: (file) => (file === 'code.tsx' ? source : ''),
      hooks: context.hooks,
    })

    // Fork to discard any cache from previous runs
    // so the CSS won't grow indefinitely
    const encoder = context.encoder.clone()
    const parserResult = project.parseSourceFile('code.tsx', encoder)
    const sheet = context.createSheet()

    const decoder = context.decoder.clone().collect(encoder)
    try {
      sheet.processDecoder(decoder)
    } catch (error) {
      console.log(error)
    }

    const cssArtifacts: CssFileArtifact[] = [
      { file: 'Utilities', code: sheet.getLayerCss('utilities') },
      { file: 'Recipes', code: sheet.getLayerCss('recipes') },
    ].concat(staticArtifacts)

    const previewCss = [css, ...cssArtifacts.map((a) => a.code ?? '')].join('\n')

    return {
      previewCss,
      artifacts,
      previewJs,
      parserResult,
      cssArtifacts,
      context,
    }
  }, [source, css, context, staticArtifacts, artifacts, previewJs])
}

export interface CssFileArtifact {
  file: string
  code: string | undefined
  dir?: string[] | undefined
}

export type UseBamboo = ReturnType<typeof useBamboo>
