import React, { useState, useEffect } from 'react'

const SCALE_MIN = -60
const SCALE_MAX = 0

function toPx (val) {
  return value2px(val, SCALE_MIN, SCALE_MAX, 0, 100)
}

function toY (val) {
  return 100 - value2px(val)
}

function MeterDefs (props) {
  const { width } = props
  let green = [0, toPx(-8)]
  let yellow = [toPx(-8), toPx(-5)]
  let red = [toPx(-5), toPx(0)]
  const common = { x: 0, width }

  return (
    <defs>
      <g id='peakbg'>
        <rect
          y={100 - red[1]}
          height={100 - red[0]}
          {...common}
          {...style('#ff2244')}
        />
        <rect
          y={100 - yellow[1]}
          height={100 - yellow[0]}
          {...common}
          {...style('#eeee00')}
        />
        <rect
          y={100 - green[1]}
          height={100 - green[0]}
          {...common}
          {...style('#88ff00')}
        />
      </g>

      <linearGradient id='fadeGrad' y2='0' x2='1'>
        <stop offset='0' stopColor='white' stopOpacity='0.2' />
        <stop offset='0.5' stopColor='white' stopOpacity='0.5' />
        <stop offset='1' stopColor='white' stopOpacity='0.2' />
      </linearGradient>

      <mask id='bgfade' maskContentUnits='objectBoundingBox'>
        <rect width='1' height='1' fill='url(#fadeGrad)' />
      </mask>
    </defs>
  )
}

let max = 0
let last = 0
function getMax (time, val) {
  // let newmax = Math.max(val, max)
  if (val > max) {
    max = val
    last = time
  } else if (time - last > 3) {
    max = val
  } else if (time - last > 1) {
    max = max - 1
    // max = val
  }
  return max
}

export function EbuMeter (props) {
  const { value } = props
  const val = value
  // let [max, setMax] = useState(0)

  const width = 40
  const gutter = 1

  let min = SCALE_MIN

  // let min = -30 // mic
  // let peakMax = -2
  // let ebuMax = -5
  let peakMax = SCALE_MAX
  let ebuMax = SCALE_MAX

  // Momentary peak
  // let peakM = value2px(val.M, min, ebuMax, 0, 100)
  // Short-term peak
  let peakS = value2px(val.S, min, ebuMax, 0, 100)
  let peakL = 0
  let peakR = 0

  if (val.FTPK) {
    peakL = value2px(val.FTPK[0], min, peakMax, 0, 100)
    peakR = value2px(val.FTPK[1], min, peakMax, 0, 100)
  }

  if (peakL > 100) peakL = 0
  if (peakR > 100) peakR = 0
  if (peakS > 100) peakS = 0

  let max = getMax(val.t, Math.max(peakL, peakR))
  
  const meterWidth = width / 2 - gutter / 2
  const peakMeterL = {
    id: 'peakL',
    peak: peakL,
    x: 0,
    width: meterWidth
  }
  const peakMeterR = {
    id: 'peakR',
    peak: peakR,
    x: meterWidth + gutter,
    width: meterWidth
  }
  return (
    <svg
      xmlns='http://www.w3.org/2000/svg'
      width='100%'
      heigh='100%'
      viewBox={`0 0 ${width} 100`}
      preserveAspectRatio='xMaxYMax meet'
    >
      <MeterDefs width={width} />

      <PeakMeter {...peakMeterL} />
      <PeakMeter {...peakMeterR} />

      {/* <rect y={100 - max} x='0' width={width} height='0.8' fill='#a9f' /> */}
    </svg>
  )
}

function PeakMeter (props = {}) {
  const { peak, width, x, id } = props
  const mask = {
    y: 100 - peak,
    height: peak,
    x,
    width
  }

  // const range = -60
  // const gutter = 0.5
  // const steps = 24
  // const dbPerStep = range / steps
  // const scale = new Array(steps).fill(null).map((_, i) => {
  //   const bottom = toPx(dbPerStep * (i)) - gutter
  //   const top = toPx(dbPerStep * (i + 1))
  //   let fill = '#fff'
  //   // if (bottom > peak) fill = '#444'
  //   return {
  //     fill,
  //     x,
  //     width,
  //     y: 100 - top,
  //     height: top - bottom
  //   }
  // })

  const height = 100
  const gutter = 0.8
  const steps = 24
  const heightPerStep = height / steps
  // const filledSteps = Math.ceil(peak / steps)
  const scale = new Array(steps).fill(null).map((_, i) => {
    const bottom = heightPerStep * i
    const top = bottom + heightPerStep - gutter
    let fill = 'white'
    if (((top + bottom) / 2) > peak) fill = '#444'
    // if ((steps * i) > peak) return
    // const y = 100 - heightPerStep * i
    return {
      fill,
      x,
      width,
      y: 100 - top,
      height: top - bottom
    }
  }).filter(x => x)
  return (
    <>
      <defs>
        <mask id={id}>
          <rect fill='#000' {...mask} />
          {scale.map((rect, i) => <rect key={i} {...rect} />)}
        </mask>
      </defs>
      <g
        mask={`url(#${id})`}
        style={{ opacity: 0.9 }}
      >
        <use xlinkHref='#peakbg' />
      </g>
    </>
  )
}

function sigLog (n) {
  return Math.log(Math.abs(n) + 1) / Math.log(10) * sig(n)
}

function sig (n) {
  return n === 0 ? 0 : Math.abs(n) / n
}

function sigExp (n) {
  return (Math.pow(10, Math.abs(n)) - 1) * sig(n)
}

function value2px (value, valueMin, valueMax, pxMin, pxMax) {
  if (value < valueMin) value = valueMin
  if (value > valueMax) value = valueMax
  if (isNaN(value) || value === null) value = valueMin

  const valueWidth = valueMax - valueMin
  const pixelWidth = pxMax - pxMin
  const ratio = pixelWidth / valueWidth
  return ratio * (value - valueMin) + pxMin

  // const ratio = value / (valueMax - valueMin)
  // const scaled = ratio * (pxMax - pxMin)
  // return pxMin + scaled
}

// This is the original function that display the meter in a log scale.
function value2pxLog (value, valueMin, valueMax, pxMin, pxMax) {
  var valueWidth = sigLog(valueMax) - sigLog(valueMin)
  var pixelWidth = pxMax - pxMin
  var ratio = pixelWidth / valueWidth

  return ratio * (sigLog(value) - sigLog(valueMin)) + pxMin
}

function px2value (px, valueMin, valueMax, pxMin, pxMax) {
  var valueWidth = sigLog(valueMax) - sigLog(valueMin)
  var pixelWidth = pxMax - pxMin
  var ratio = pixelWidth / valueWidth

  return sigExp((px - pxMin) / ratio + sigLog(valueMin))
}

function prettify (n) {
  var exp = Math.round(Math.pow(10, Math.log(Math.abs(n)) / Math.log(10)))
  return exp === 0 ? 0 : Math.round(n / exp) * exp
}

function style (color) {
  return { style: { fill: color } }
}
