// Dependencies
import { linkClasses, formatNumber, orderBy, clone } from '@freesewing/utils'
// Hooks
import React, { useState, useEffect } from 'react'
import { useBackend } from '@freesewing/react/hooks/useBackend'
// Components
import { Spinner } from '@freesewing/react/components/Spinner'
import { Link as WebLink } from '@freesewing/react/components/Link'
import { ChartWrapper } from '@freesewing/react/components/Echart'

const meta = {
  title: 'FreeSewing by numbers',
  description: 'Some high-level numbers about Freesewing',
}

const option = {
  tooltip: {
    trigger: 'axis',
    show: true,
    axisPointer: {
      type: 'line',
      lineStyle: {
        type: 'dashed',
      },
    },
  },
  title: {
    left: 'center',
  },
  grid: {
    left: '40',
    right: '60',
    containLabel: true,
  },
  toolbox: {
    feature: {
      saveAsImage: {},
      magicType: {
        type: ['line', 'bar'],
      },
    },
  },
  yAxis: {
    type: 'value',
  },
}

/**
 * A component to display generic stats from the FreeSewing backend
 *
 * @component
 * @param {object} props - All component props
 * @param {React.FC} [props.Link = false] - An optional framework-specific Link component
 * @returns {JSX.Element}
 */
export const Stats = ({ Link = false }) => {
  if (!Link) Link = WebLink
  const [stats, setStats] = useState()
  const [error, setError] = useState(false)
  const backend = useBackend()

  useEffect(() => {
    getStats(backend, setStats, setError)
  }, [])

  if (!stats)
    return (
      <div className="tw:text-center tw:mt-12 tw:w-full">
        <Spinner />
      </div>
    )

  const designTop = orderBy(
    Object.entries(stats.designs).map(([design, count]) => ({ design, count })),
    'count',
    'desc'
  ).slice(0, 50)

  const optionD = clone(option)
  optionD.title.text = 'Top 50 FreeSewing Designs'
  optionD.xAxis = {
    type: 'category',
    data: designTop.map((entry) => entry.design),
    name: 'Design',
  }
  optionD.series = [
    {
      data: designTop.map((entry) => entry.count),
      type: 'bar',
    },
  ]

  const optionU = clone(option)
  optionU.title.text = 'Top 25 FreeSewing Users'
  optionU.xAxis = {
    type: 'category',
    data: stats.topUsers.map((user) => user.username),
    name: 'User',
  }
  optionU.series = [
    {
      data: stats.topUsers.map((user) => user.calls),
      type: 'bar',
    },
  ]

  return (
    <>
      <div className="tw:max-w-7xl tw:mx-auto tw:my-12 tw:px-4">
        <div className="tw:grid tw:grid-cols-1 tw:md:grid-cols-2 tw:gap-2">
          <Stat title="Users" value={stats.user} />
          <Stat title="Patterns" value={stats.pattern} />
          <Stat title="Measurements Sets" value={stats.set} />
          <Stat title="Curated Sets" value={stats.curatedSet} />
          <Stat title="Bookmarks" value={stats.bookmark} />
          <Stat title="API Keys" value={stats.apikey} />
          <Stat title="JWT Calls" value={stats.activity.jwt} desc="Total Number Seen" />
          <Stat title="API Key Calls" value={stats.activity.key} desc="Total Number Seen" />
        </div>
        <h2>Top Users</h2>
        <ChartWrapper option={optionU} />
        <small className="tw:ml-4 tw:py-1 tw:opacity-80">
          <b>Note:</b> Ordered by JWT calls made to the FreeSewing backend
        </small>
        <div className="tw:max-h-96 tw:overflow-scroll">
          <ol className="tw:list tw:list-inside tw:list-decimal tw:ml-4">
            {stats.topUsers.map((u) => (
              <li key={u.id}>
                <Link href={`/users/?id=${u.id}`} className={linkClasses}>
                  {u.username}
                </Link>
                : {formatNumber(u.calls)}
              </li>
            ))}
          </ol>
        </div>
        <h2>Top Designs</h2>
        <ChartWrapper option={optionD} />
        <small className="tw:ml-4 tw:py-1 tw:opacity-80">
          <b>Note:</b> Ordered by patterns stored in the FreeSewing backend
        </small>
        <div className="tw:max-h-96 tw:overflow-scroll">
          <ol className="tw:list tw:list-inside tw:list-decimal tw:ml-4">
            {Object.entries(stats.designs).map(([d, c]) => (
              <li key={d}>
                <Link href={`/designs/${d}`} className={linkClasses}>
                  <span className="tw:capitalize">{d}</span>
                </Link>
                : {formatNumber(c)}
              </li>
            ))}
          </ol>
        </div>
      </div>
    </>
  )
}

const Stat = ({ title, value, desc = 'Total Number Stored' }) => (
  <div className="tw:daisy-stats tw:shadow">
    <div className="tw:daisy-stat">
      <div className="tw:daisy-stat-title">{title}</div>
      <div className="tw:daisy-stat-value">{formatNumber(value)}</div>
      <div className="tw:daisy-stat-desc">{desc}</div>
    </div>
  </div>
)

const getStats = async (backend, setStats, setError) => {
  const result = await backend.getStats()
  if (result[0] === 200 && result[1]) setStats(result[1])
  else setError(true)
}