import React from 'react'
import ReactApexChart from 'react-apexcharts'
import ApexCharts from 'apexcharts'
import './styles.css'

// A wandering line (numeric x, ~45 points) so there is room to zoom, pan,
// annotate and measure. Randomize regenerates it into a fresh checkpoint.
function randomSeries() {
  var d = []
  var v = 45 + Math.random() * 25
  for (var i = 0; i < 45; i++) {
    v += (Math.random() - 0.5) * 22
    if (v < 8) v = 8
    if (v > 100) v = 100
    d.push([i + 1, Math.round(v)])
  }
  return d
}

const ApexChart = () => {
  const [state, setState] = React.useState({
    series: [{ name: 'Value', data: randomSeries() }],
    options: {
      chart: {
        height: 400,
        type: 'line',
        id: 'rewind-demo',
        fontFamily: 'Helvetica, Arial, sans-serif',
        animations: { enabled: true },
        // Toolbar on so zoom / pan / reset (and the measure tool) are one click away.
        toolbar: { show: true, autoSelected: 'zoom' },
        zoom: { enabled: true, type: 'x' },
        history: {
          enabled: true,
          maxDepth: 50,
          coalesceMs: 250,
          keyboard: true,
        },
        // Right-click actions: drop a note, a dashed marker line, or seed the ruler.
        contextMenu: {
          enabled: true,
          line: { text: 'Marker', strokeDashArray: 5, color: '#0EA5E9' },
          items: ['annotate', 'xline', 'yline', 'measure'],
        },
        // Measure ruler + editable / draggable annotations. Both commit checkpoints,
        // so Undo / Redo steps through them alongside data and zoom changes.
        measure: { enabled: true },
        ink: { enabled: true, snap: true },
      },
      colors: ['#0EA5E9'],
      stroke: { width: 2.5, curve: 'smooth' },
      markers: { size: 0, hover: { size: 5 } },
      dataLabels: { enabled: false },
      title: {
        text: 'Undo / redo over data, zoom, annotations, and measurements',
        align: 'left',
      },
      xaxis: { type: 'numeric', title: { text: 'Session' }, tickAmount: 10 },
      yaxis: { decimalsInFloat: 0 },
      grid: { borderColor: '#eceff5' },
    },
  })

  React.useEffect(() => {
    // The react-apexcharts wrapper owns the render, so reach the live instance by
    // its chart.id, then wire the same buttons the vanilla build does.
    // (randomSeries lives in the shared head script.) History drives the chart
    // instance directly, so no React state changes and the chart is never
    // re-rendered under it.
    let chart
    const timer = window.setInterval(() => {
      chart = ApexCharts.getChartByID('rewind-demo')
      if (!chart) return
      window.clearInterval(timer)

      const undoBtn = document.getElementById('undo')
      const redoBtn = document.getElementById('redo')
      const readout = document.getElementById('readout')

      function syncButtons(state) {
        if (!state) state = chart.history.state()
        undoBtn.disabled = !state.canUndo
        redoBtn.disabled = !state.canRedo
        readout.innerHTML =
          'history: <b>' +
          (state.index + 1) +
          ' / ' +
          state.length +
          '</b> checkpoints'
      }

      chart.addEventListener('historyChange', function (c, state) {
        syncButtons(state && state.length != null ? state : undefined)
      })

      undoBtn.addEventListener('click', function () {
        chart.history.undo()
      })
      redoBtn.addEventListener('click', function () {
        chart.history.redo()
      })
      document
        .getElementById('randomize')
        .addEventListener('click', function () {
          chart.updateSeries([{ name: 'Value', data: randomSeries() }])
        })
      document.getElementById('reset').addEventListener('click', function () {
        chart.history.clear()
      })

      // initial state once the baseline checkpoint lands
      window.setTimeout(syncButtons, 300)
    }, 50)

    return () => {
      window.clearInterval(timer)
    }
  }, [])

  return (
    <div>
      <div className="panel">
        <div className="controls">
          <button id="undo" className="primary" disabled>
            Undo
          </button>
          <button id="redo" className="primary" disabled>
            Redo
          </button>
          <button id="randomize">Randomize data</button>
          <button id="reset">Clear history</button>
          <span className="readout" id="readout">
            history: empty
          </span>
        </div>
      </div>

      <div id="chart">
        <ReactApexChart
          options={state.options}
          series={state.series}
          type="line"
          height={400}
        />
      </div>

      <div className="panel">
        <div className="note">
          History is enabled with{' '}
          <code>chart: &#123; history: &#123; enabled: true &#125; &#125;</code>
          . Every data update, zoom, pan, annotation and measurement commits a
          checkpoint. <b>Right-click</b> the plot to add a note, drop a dashed
          marker line, or start a measurement (context menu); <b>drag-select</b>{' '}
          or use the toolbar to zoom and pan; hold <code>m</code> and drag to
          measure; press Randomize to replace the data. Then step back with Undo
          / Redo (or press
          <code>Cmd/Ctrl + Z</code> and <code>Shift + Cmd/Ctrl + Z</code>). The
          buttons enable from the <code>historyChange</code> event via
          <code>chart.history.state()</code>.
        </div>
      </div>
    </div>
  )
}

export default ApexChart
Undo / Redo (Rewind) - React Narrative & State | ApexCharts.js | ApexCharts.js