import { css, cva } from '@/styled-system/css'
import { flex } from '@/styled-system/patterns'
import type { ResultItem } from '@bamboocss/types'
import { useTheme } from 'next-themes'
import { useBamboo } from '../hooks/useBamboo'
import * as React from 'react'
import dynamic from 'next/dynamic'

const ResultItemRowJson = dynamic(() => import('./ASTViewer-row'))

export const ASTViewer = React.memo(function ASTViewer(props: {
  parserResult: ReturnType<typeof useBamboo>['parserResult']
}) {
  if (!props.parserResult) return null

  return (
    <div className={flex({ direction: 'column', gap: '8px', py: '4', h: 'full', overflow: 'auto' })}>
      {Array.from(props.parserResult.toArray()).map((result, index) => {
        return <ResultItemRow key={index} result={result} />
      })}
    </div>
  )
})

const resultType = cva({
  base: {
    py: '1',
    px: '2',
    borderRadius: 'lg',
    fontWeight: 'semibold',
    borderWidth: '1px',
  },
  variants: {
    type: {
      css: { bg: { base: 'gray.100', _dark: '#FFFFFF08' }, color: { base: 'gray.700', _dark: 'white' } },
      cva: { bg: { base: 'gray.300', _dark: '#FFFFFF12' }, color: { base: 'gray.700', _dark: 'white' } },
      sva: { bg: { base: 'gray.300', _dark: '#FFFFFF12' }, color: { base: 'gray.700', _dark: 'white' } },
      jsx: { bg: { base: 'blue.300', _dark: 'blue.500' } },
      'jsx-factory': { bg: { base: 'blue.100', _dark: 'blue.300' }, color: { _dark: 'black' } },
      pattern: { bg: { base: 'indigo.400', _dark: 'indigo.500' }, color: 'white' },
      'jsx-pattern': { bg: { base: 'indigo.400', _dark: 'indigo.500' }, color: 'white' },
      recipe: { bg: { base: 'yellow.300', _dark: 'yellow.500' }, color: { _dark: 'black' } },
      'jsx-recipe': { bg: { base: 'yellow.300', _dark: 'yellow.500' }, color: { _dark: 'black' } },
      token: { bg: { base: 'green.300', _dark: 'green.500' }, color: { _dark: 'black' } },
    },
    name: {
      cva: { bg: { base: 'teal.500', _dark: 'teal.700' }, color: 'white' },
      css: { bg: { base: 'blue.500', _dark: 'blue.700' }, color: 'white' },
    },
  },
})

const rowClassName = css({
  '&.json-viewer-theme-dark': {
    bg: 'transparent !important',
  },
  '& data-object-start, .data-object-end': {
    color: { _dark: 'white' },
  },
})

const ResultItemRow = (props: { result: ResultItem }) => {
  const { result } = props
  const { resolvedTheme } = useTheme()
  return (
    <div className={flex({ direction: 'column', gap: '8px', px: '6' })}>
      <div className={flex({ align: 'center', gap: '8px' })}>
        <span className={resultType({ type: result.type })}>{result.type}</span>{' '}
        <span className={resultType({ name: result.name as 'cva' | 'css' })}>{result.name}</span>
        <span className={css({ ml: 'auto' })}>(l{getReportRange(result)})</span>
      </div>
      <ResultItemRowJson theme={resolvedTheme} data={result.data} className={rowClassName} />
    </div>
  )
}

const getReportRange = (reportItem: ResultItem) => {
  if (!reportItem.box) return ''

  const node = reportItem.box.getNode()
  const src = node.getSourceFile()

  const startPosition = node.getStart()
  const startInfo = src.getLineAndColumnAtPos(startPosition)

  return `:${startInfo.line}:${startInfo.column}`
}
