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

// Shared by the vanilla-js, React and Vue builds.
//
// Levels are FETCHED, not inlined, which is how a real dashboard works: the
// root is small, and each child is a request. A fake backend stands in for the
// API so the demo is self-contained and deterministic.
var BACKEND = {
  '2023-q': [
    { x: 'Q1', y: 21 },
    { x: 'Q2', y: 28 },
    { x: 'Q3', y: 24 },
    { x: 'Q4', y: 27 },
  ],
  '2024-q': [
    { x: 'Q1', y: 33 },
    { x: 'Q2', y: 41 },
    { x: 'Q3', y: 36 },
    { x: 'Q4', y: 40 },
  ],
  '2025-q': [
    { x: 'Q1', y: 44 },
    { x: 'Q2', y: 52 },
    { x: 'Q3', y: 48 },
    { x: 'Q4', y: 56 },
  ],
}

// Flipped by the checkbox, so the failure path is demonstrable rather than
// described. A failed fetch must leave the chart exactly where it was.
var failNext = false

function fakeFetch(id) {
  return new Promise(function (resolve, reject) {
    window.setTimeout(function () {
      if (failNext) {
        reject(new Error('Request failed (simulated)'))
        return
      }
      var rows = BACKEND[id]
      if (!rows) {
        reject(new Error('No level "' + id + '"'))
        return
      }
      resolve({ id: id, name: id.replace('-q', ' by quarter'), data: rows })
    }, 700)
  })
}

function setStatus(text, isError) {
  var el = document.querySelector('#status')
  if (!el) return
  el.textContent = text || ''
  el.className = isError ? 'status error' : 'status'
}

const ApexChart = () => {
  const [state, setState] = React.useState({
    series: [
      {
        name: 'Revenue',
        data: [
          { x: '2023', y: 100, drilldown: '2023-q' },
          { x: '2024', y: 150, drilldown: '2024-q' },
          { x: '2025', y: 200, drilldown: '2025-q' },
        ],
      },
    ],
    options: {
      chart: {
        id: 'asyncDrill',
        type: 'bar',
        height: 400,
        toolbar: {
          show: false,
        },
      },
      plotOptions: {
        bar: {
          distributed: true,
          columnWidth: '50%',
          borderRadius: 6,
          borderRadiusApplication: 'end',
        },
      },
      legend: {
        show: false,
      },
      dataLabels: {
        enabled: false,
      },
      drilldown: {
        enabled: true,
        // Deliberately empty: every level below the root comes from onDrillDown.
        series: [],
        breadcrumb: {
          show: true,
          rootLabel: 'All years',
        },
        loading: {
          show: true,
        },
        cache: true,
      },
    },
  })

  React.useEffect(() => {
    // The react-apexcharts wrapper owns the render, so reach the live instance by
    // its chart.id, then wire the resolver and controls. (BACKEND/fakeFetch/
    // setStatus live in the shared head script.)
    let chart

    const timer = window.setInterval(() => {
      chart = ApexCharts.getChartByID('asyncDrill')
      if (!chart) return
      window.clearInterval(timer)

      chart.updateOptions({
        drilldown: {
          onDrillDown: (ctx) => {
            setStatus('Fetching ' + ctx.id + '...')
            return fakeFetch(ctx.id)
          },
        },
      })

      chart.addEventListener('drillDownEnd', () => setStatus(''))
      chart.addEventListener('drillDownError', (info) =>
        setStatus(String(info.error && info.error.message), true),
      )

      document
        .querySelector('#up')
        .addEventListener('click', () => chart.drillUp())
      document.querySelector('#clear-cache').addEventListener('click', () => {
        chart.clearDrilldownCache()
        setStatus('Cache cleared - the next drill will refetch.')
      })
      document.querySelector('#fail').addEventListener('change', (e) => {
        failNext = e.target.checked
      })
    }, 50)

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

  return (
    <div>
      <div className="wrap">
        <h1>Drilldown against a real backend</h1>
        <p>
          The root shows three years. Each year's quarters are fetched on click,
          with a spinner while the request is in flight. Levels are cached, so
          drilling back down a branch you have already visited is instant. Tick
          "make the next request fail" to see that a failed fetch leaves the
          chart exactly where it was and reports the error, rather than
          stranding the view.
        </p>

        <div className="actions">
          <button id="up">Back</button>
          <button id="clear-cache">Clear cache</button>
          <label>
            <input type="checkbox" id="fail" />
            Make the next request fail
          </label>
        </div>

        <div className="chart-wrap">
          <div id="chart">
            <ReactApexChart
              options={state.options}
              series={state.series}
              type="bar"
              height={400}
            />
          </div>
        </div>

        <div className="status" id="status"></div>
      </div>
    </div>
  )
}

export default ApexChart
Async Drilldown Column - React Column Charts | ApexCharts.js | ApexCharts.js