import { prunesPreflight } from '@bamboocss/core'
import { logger } from '@bamboocss/logger'
import type { CssArtifactType } from '@bamboocss/types'
import type { BambooContext } from './create-context'
import {
  collectKeyframeReferences,
  collectRenderedElements,
  keyframeNames,
  pruneTokensForBuild,
} from './token-references'

export interface CssGenOptions {
  cwd: string
  outfile?: string
  type?: CssArtifactType
  splitting?: boolean
}

export const cssgen = async (ctx: BambooContext, options: CssGenOptions) => {
  const { outfile, type, splitting } = options

  const sheet = ctx.createSheet()

  if (type) {
    const done = logger.time.info(ctx.messages.cssArtifactComplete(type))

    ctx.appendCssOfType(type, sheet)

    // The token and keyframe passes cannot run here: both decide reachability by reading
    // the finished stylesheet, and this branch emits one artifact, so everything would look
    // unreachable. `preflight.prune` reads the source instead of the sheet, so a partial one
    // costs it nothing -- and without this the `reset.css` from `cssgen preflight` differs
    // from the one `cssgen --splitting` writes for the same project.
    //
    // Note this branch never calls `parseFiles`, which `collectRenderedElements` does not
    // need: it reads the files itself rather than anything parsing leaves behind.
    if (type === 'preflight' && prunesPreflight(ctx.config.preflight)) {
      ctx.prunePreflight(sheet, collectRenderedElements(ctx))
    }

    if (outfile) {
      const css = ctx.getCss(sheet)
      logger.info('css', ctx.runtime.path.resolve(outfile))
      await ctx.runtime.fs.writeFile(outfile, css)
    } else {
      await ctx.writeCss(sheet)
    }

    done()
  } else {
    const { files, results } = ctx.parseFiles()

    const done = logger.time.info(ctx.messages.buildComplete(files.length))

    ctx.appendLayerParams(sheet)
    ctx.appendBaselineCss(sheet)
    ctx.appendParserCss(sheet)

    // Only now does the sheet hold everything that could reference a token. Gathering the
    // references reads every source file, so each pass stays behind its own flag.
    const reachableVars = pruneTokensForBuild(ctx, sheet, results)

    if (prunesPreflight(ctx.config.preflight)) {
      ctx.prunePreflight(sheet, collectRenderedElements(ctx))
    }

    if (ctx.config.prune?.keyframes) {
      ctx.pruneKeyframes(sheet, collectKeyframeReferences(ctx, keyframeNames(ctx)), reachableVars)
    }

    if (splitting) {
      await ctx.writeSplitCss(sheet)
    } else if (outfile) {
      const css = ctx.getCss(sheet)
      logger.info('css', ctx.runtime.path.resolve(outfile))
      await ctx.runtime.fs.writeFile(outfile, css)
    } else {
      await ctx.writeCss(sheet)
    }

    done()
  }
}
