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

import 'apexcharts/features/trellis'

// Forty-two markets, three years of monthly activation rate, no axes at all.
// At this size an axis costs more than it pays: the shared scale is stated
// once in the caption, each panel labels its own latest value, and the ink
// left over is the trend. The five best and five weakest latest rates are
// tinted so the extremes are findable without reading 42 numbers.
//
// Deterministic series so the e2e snapshot is stable.
function mulberry32(seed) {
  return function () {
    seed |= 0
    seed = (seed + 0x6d2b79f5) | 0
    var t = Math.imul(seed ^ (seed >>> 15), 1 | seed)
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296
  }
}

var MARKETS = [
  'Amsterdam',
  'Antwerp',
  'Athens',
  'Auckland',
  'Austin',
  'Bergen',
  'Bilbao',
  'Bologna',
  'Bristol',
  'Calgary',
  'Cardiff',
  'Cork',
  'Dublin',
  'Dundee',
  'Edinburgh',
  'Galway',
  'Ghent',
  'Graz',
  'Helsinki',
  'Kingston',
  'Leeds',
  'Leiden',
  'Lisbon',
  'Lyon',
  'Malaga',
  'Malmo',
  'Nantes',
  'Oporto',
  'Oslo',
  'Ottawa',
  'Padua',
  'Perth',
  'Reykjavik',
  'Rotterdam',
  'Salerno',
  'Seville',
  'Tampere',
  'Turin',
  'Turku',
  'Utrecht',
  'Verona',
  'Zurich',
]

var MONTHS = 36
var START = new Date(2023, 0, 1).getTime()
var MONTH_MS = 30.44 * 24 * 3600 * 1000

// A trend plus a wobble, so the panels have shape rather than noise.
function activationSeries(seed, start, drift) {
  var rand = mulberry32(seed)
  var out = []
  var v = start
  for (var m = 0; m < MONTHS; m++) {
    v += drift + (rand() - 0.5) * 0.55
    // A mild seasonal lift in the second half of each year.
    var season = Math.sin(((m % 12) / 12) * Math.PI * 2) * 0.28
    out.push({
      x: Math.round(START + m * MONTH_MS),
      y: Math.max(1.2, Math.round((v + season) * 100) / 100),
    })
  }
  return out
}

var marketSeries = MARKETS.map(function (name, i) {
  var rand = mulberry32(1000 + i * 13)
  var start = 2.4 + rand() * 3.2
  var drift = (rand() - 0.42) * 0.11
  return {
    name: 'Activation rate',
    market: name,
    data: activationSeries(200 + i * 7, start, drift),
  }
})

// Rank on the LATEST value: the five best get the teal tint, the five
// weakest the amber one, everything else stays quiet grey.
var latest = {}
marketSeries.forEach(function (s) {
  latest[s.market] = s.data[s.data.length - 1].y
})
var ranked = MARKETS.slice().sort(function (a, b) {
  return latest[b] - latest[a]
})
var TOP = {}
var BOTTOM = {}
ranked.slice(0, 5).forEach(function (m) {
  TOP[m] = true
})
ranked.slice(-5).forEach(function (m) {
  BOTTOM[m] = true
})

const ApexChart = () => {
  const [state, setState] = React.useState({
    series: marketSeries,
    options: {
      chart: {
        id: 'marketTrellis',
        type: 'line',
        height: 700,
        animations: {
          enabled: false,
        },
      },
      trellis: {
        by: 'market',
        columns: 7,
        minPanelWidth: 130,
        panelHeight: 76,
        gap: 6,
        header: {
          style: {
            fontSize: '11px',
            fontWeight: 600,
          },
        },
        panel: function (key) {
          // The value label rides the last point, so which SIDE of it has room
          // depends on where that point sits in the shared 0-10 frame: below for a
          // high panel, above for a low one. `panel()` is merged last, so the
          // per-panel offset is a two-line override.
          var side = { dataLabels: { offsetY: latest[key] > 5 ? 15 : -8 } }
          if (TOP[key]) {
            return Object.assign(
              { colors: ['#0F766E'], chart: { background: '#EAF4F2' } },
              side,
            )
          }
          if (BOTTOM[key]) {
            return Object.assign(
              { colors: ['#B45309'], chart: { background: '#FBF1E3' } },
              side,
            )
          }
          return Object.assign({ colors: ['#94A3B8'] }, side)
        },
      },
      stroke: {
        width: 1.5,
        curve: 'straight',
      },
      markers: {
        size: 0,
        discrete: [
          {
            seriesIndex: 0,
            dataPointIndex: 35,
            size: 3,
            strokeWidth: 0,
          },
        ],
      },
      dataLabels: {
        enabled: true,
        offsetX: -10,
        offsetY: -8,
        background: {
          enabled: false,
        },
        style: {
          fontSize: '10px',
          fontWeight: 600,
          colors: ['#475569'],
        },
        formatter: function (val, opts) {
          var d = opts.w.config.series[opts.seriesIndex].data
          return opts.dataPointIndex === d.length - 1
            ? Number(val).toFixed(1)
            : ''
        },
      },
      yaxis: {
        labels: {
          show: false,
        },
      },
      xaxis: {
        type: 'datetime',
        labels: {
          show: false,
        },
        axisTicks: {
          show: false,
        },
        axisBorder: {
          show: false,
        },
        tooltip: {
          enabled: false,
        },
      },
      grid: {
        show: false,
        padding: {
          left: 4,
          right: 4,
        },
      },
      tooltip: {
        x: {
          format: 'MMM yyyy',
        },
      },
    },
  })

  return (
    <div>
      <div className="wrap">
        <h1>Activation rate by market, 2023 to 2025</h1>
        <p className="lead">
          Forty-two panels, no axes, one shared scale stated once. Every panel
          labels its own latest value, so the grid stays readable at 42 markets
          where a 42-series line chart is a hairball and a 42-row table is
          homework.
        </p>
        <p className="key">
          <span className="up">Top 5</span> vs{' '}
          <span className="down">Bottom 5</span>
          <span className="rest">
            by latest rate, all panels on a shared 0-10% scale
          </span>
        </p>

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

        <div className="note">
          Dropping the axes is the user's own options, not a trellis mode: turn
          the labels, ticks, borders and gridlines off and every panel loses the
          same space, so the panels stay pixel-aligned. The conditional tint
          comes from
          <code>trellis.panel</code>, which is merged last and can therefore
          override anything, here a <code>chart.background</code> and a stroke
          colour per panel. Every cell also carries its facet key as
          <code>data-key</code>, so plain CSS can style the panel chrome (the
          header, the border) the same way. Hovering gives a one-line tooltip
          rather than a card: panels this short get <code>tooltip.compact</code>
          automatically (set it yourself, either way, and the trellis leaves the
          decision alone). Trellis is a premium feature; without a license it
          renders with a trial watermark.
        </div>
      </div>
    </div>
  )
}

export default ApexChart