<template>
  <div
    :style="boxStyle"
    class="relative overflow-hidden box-border flex items-center justify-center"
  >
    <canvas ref="barcodeCanvas" class="w-full h-full block"></canvas>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, watch, onMounted } from 'vue'
import { useWidgetStyle } from '../hooks/useWidgetStyle'
import { encodeCode128B } from './code128'
import { useProjectStore } from '@/store/modules/project'

const DEFAULT_TEXT = 'https://www.sv-elec.com/'
const DEFAULT_SCALE = 1
const BASE_THICKNESS = 60

const props = defineProps<{
  id?: string
  width: number
  height: number
  styles: any
  state?: string
  part?: string
  lightColor?: string
  darkColor?: string
  scale?: number
  direction?: 'horizontal' | 'vertical'
  text?: string
}>()

const barcodeCanvas = ref<HTMLCanvasElement | null>(null)
const projectStore = useProjectStore()

const styleMap = useWidgetStyle({
  widget: 'barcode',
  props
})

const boxStyle = computed(() => {
  return {
    width: `${props.width}px`,
    height: `${props.height}px`,
    ...(styleMap.value?.mainStyle || {})
  }
})

const getAutoWidth = () => {
  const pattern =
    encodeCode128B((props.text || DEFAULT_TEXT).trim() || DEFAULT_TEXT) ||
    encodeCode128B(DEFAULT_TEXT)
  const totalUnits = pattern?.reduce((sum, unit) => sum + unit, 0) || 1
  const scale = Math.max(1, Math.min(5, Math.round(Number(props.scale) || DEFAULT_SCALE)))

  return props.direction === 'vertical' ? BASE_THICKNESS * scale : totalUnits * scale
}

const syncWidgetWidth = () => {
  if (!props.id) return

  const widget = projectStore.getWidgetById(props.id)
  if (!widget?.props) return

  const nextWidth = getAutoWidth()
  if (widget.props.width !== nextWidth) {
    widget.props.width = nextWidth
  }
}

const renderBarcode = () => {
  if (!barcodeCanvas.value) return

  const canvas = barcodeCanvas.value
  const context = canvas.getContext('2d')
  if (!context) return

  const width = Math.max(1, props.width || 1)
  const height = Math.max(1, props.height || 1)

  canvas.width = width
  canvas.height = height

  context.clearRect(0, 0, width, height)
  context.fillStyle = props.lightColor || '#ffffff'
  context.fillRect(0, 0, width, height)

  const pattern = encodeCode128B((props.text || DEFAULT_TEXT).trim() || DEFAULT_TEXT)
  if (!pattern?.length) {
    console.error('Failed to render barcode: unsupported content')
    return
  }

  const totalUnits = pattern.reduce((sum, unit) => sum + unit, 0)
  const isVertical = props.direction === 'vertical'
  const moduleSize = (isVertical ? height : width) / totalUnits

  let offset = 0
  let isBar = true

  context.fillStyle = props.darkColor || '#000000'
  pattern.forEach((unit) => {
    const segmentSize = unit * moduleSize
    if (isBar) {
      if (isVertical) {
        context.fillRect(0, offset, width, segmentSize)
      } else {
        context.fillRect(offset, 0, segmentSize, height)
      }
    }
    offset += segmentSize
    isBar = !isBar
  })
}

watch(
  () => [props.width, props.height, props.text, props.darkColor, props.lightColor, props.direction],
  () => {
    renderBarcode()
  },
  { immediate: true, flush: 'post' }
)

watch(
  () => [props.id, props.text, props.scale, props.direction],
  () => {
    syncWidgetWidth()
  },
  { immediate: true, flush: 'post' }
)

onMounted(() => {
  renderBarcode()
})
</script>
