import { useMemo, useState } from 'react'
import { Card, Segmented, Flex, Popover, DatePicker, Button, Space } from 'antd'
import {
  ResponsiveContainer,
  BarChart,
  Bar,
  LineChart,
  Line,
  CartesianGrid,
  XAxis,
  YAxis,
  Tooltip,
  Legend
} from 'recharts'

import PropTypes from 'prop-types'
import dayjs from 'dayjs'
import { useThemeContext } from '../context/ThemeContext'
import MissingPlaceholder from './MissingPlaceholder'
import CheckIcon from '../../Icons/CheckIcon'
import { LoadingOutlined } from '@ant-design/icons'

const HISTORY_SERIES_CONFIG = {
  filamentStock: {
    series: [
      {
        key: 'currentWeight.net',
        label: 'Net Weight',
        color: 'processing',
        suffix: 'g'
      },
      {
        key: 'currentWeight.gross',
        label: 'Gross Weight',
        color: 'warning',
        suffix: 'g'
      }
    ],
    formatValue: (value, suffix = '') =>
      `${Number(value ?? 0).toFixed(2)}${suffix}`
  },
  partStock: {
    series: [
      {
        key: 'currentQuantity',
        label: 'Current Quantity',
        color: 'processing'
      }
    ],
    formatValue: (value) => Number(value ?? 0).toFixed(2)
  },
  productStock: {
    series: [
      {
        key: 'currentQuantity',
        label: 'Current Quantity',
        color: 'processing'
      }
    ],
    formatValue: (value) => Number(value ?? 0).toFixed(2)
  },
  stockEvent: {
    series: [
      {
        key: 'value',
        label: 'Value',
        color: 'processing',
        variance: true
      }
    ],
    formatValue: (value, suffix = '') => {
      const numericValue = Number(value ?? 0)
      const isPositive = numericValue > 0
      const isNegative = numericValue < 0
      return `${isPositive ? '+' : isNegative ? '-' : ''}${Math.abs(numericValue).toFixed(2)}${suffix}`
    }
  }
}

const getNestedValue = (obj, path) => {
  if (!obj || !path) return undefined
  const keys = path.split('.')
  let value = obj
  for (const key of keys) {
    if (value === null || value === undefined) return undefined
    value = value[key]
  }
  return value
}

const HistoryDisplay = ({
  loading = false,
  history = [],
  objectType,
  chartType = 'bar',
  unit,
  startDate,
  endDate,
  styles,
  height = 400
}) => {
  const [timeRange, setTimeRange] = useState('4hrs')
  const [startCustomDate, setStartCustomDate] = useState(null)
  const [endCustomDate, setEndCustomDate] = useState(null)
  const { isDarkMode, getColors } = useThemeContext()

  const config = HISTORY_SERIES_CONFIG[objectType]

  const { defaultStartDate, defaultEndDate } = useMemo(() => {
    const now = new Date()

    if (startDate || endDate) {
      return {
        defaultStartDate:
          startDate || new Date(now.getTime() - 24 * 60 * 60 * 1000),
        defaultEndDate: endDate || now
      }
    }

    if (timeRange === 'custom' && startCustomDate && endCustomDate) {
      return {
        defaultStartDate: startCustomDate.toDate(),
        defaultEndDate: endCustomDate.toDate()
      }
    }

    const timeRangeMap = {
      '24hrs': 24 * 60,
      '12hrs': 12 * 60,
      '8hrs': 8 * 60,
      '4hrs': 4 * 60,
      '1hrs': 60,
      '30mins': 30,
      '15mins': 15,
      '5mins': 5
    }
    const minutes = timeRangeMap[timeRange] || 60
    return {
      defaultStartDate: new Date(now.getTime() - minutes * 60 * 1000),
      defaultEndDate: now
    }
  }, [startDate, endDate, timeRange, startCustomDate, endCustomDate])

  const chartRows = useMemo(() => {
    if (!config || !Array.isArray(history)) {
      return []
    }

    const start = new Date(defaultStartDate).getTime()
    const end = new Date(defaultEndDate).getTime()

    return history
      .filter((point) => {
        const timestamp = new Date(point.timestamp).getTime()
        return timestamp >= start && timestamp <= end
      })
      .map((point) => {
        const row = {
          timestamp: point.timestamp,
          dateFormatted: dayjs(point.timestamp).format('DD/MM HH:mm')
        }

        config.series.forEach((seriesDef) => {
          row[seriesDef.label] = getNestedValue(point, seriesDef.key) ?? 0
        })

        return row
      })
      .sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp))
  }, [history, config, defaultStartDate, defaultEndDate])

  if (!objectType || !config) {
    return null
  }

  const themeColors = getColors()
  const colors = {
    success: themeColors.colorSuccess,
    processing: themeColors.colorInfo,
    error: themeColors.colorError,
    warning: themeColors.colorWarning,
    default: '#8c8c8c',
    cyan: themeColors.colorCyan,
    pink: themeColors.colorPink,
    purple: themeColors.colorPurple,
    magenta: themeColors.colorMagenta,
    volcano: themeColors.colorVolcano
  }

  const colorRange = config.series.map((seriesDef) => {
    if (seriesDef.color) {
      return colors[seriesDef.color] || seriesDef.color
    }
    return colors.default
  })

  const formatTooltipValue = (value, seriesLabel) => {
    const seriesDef = config.series.find((item) => item.label === seriesLabel)
    const suffix = seriesDef?.suffix || unit || ''
    return config.formatValue(value, suffix)
  }

  const customTimeRangeContent = (
    <Space.Compact>
      <DatePicker.RangePicker
        onChange={(dates) => {
          if (dates) {
            setStartCustomDate(dates[0])
            setEndCustomDate(dates[1])
          } else {
            setStartCustomDate(null)
            setEndCustomDate(null)
          }
        }}
        value={[startCustomDate, endCustomDate]}
      />
      <Button
        type='primary'
        onClick={() => {
          if (startCustomDate && endCustomDate) {
            setTimeRange('custom')
          }
        }}
        disabled={!startCustomDate || !endCustomDate}
        icon={<CheckIcon />}
      ></Button>
    </Space.Compact>
  )

  const chartProps = {
    data: chartRows
  }

  const axisTickStyle = {
    fill: isDarkMode ? '#d9d9d9' : '#595959',
    fontSize: 12
  }

  const tooltipStyle = {
    backgroundColor: isDarkMode ? '#1f1f1f' : '#ffffff',
    border: `1px solid ${isDarkMode ? '#303030' : '#f0f0f0'}`,
    borderRadius: 8
  }

  const renderChart = () => {
    const commonElements = (
      <>
        <CartesianGrid
          strokeDasharray='3 3'
          stroke={isDarkMode ? '#303030' : '#f0f0f0'}
        />
        <XAxis dataKey='dateFormatted' tick={axisTickStyle} />
        <YAxis tick={axisTickStyle} />
        <Tooltip
          contentStyle={tooltipStyle}
          formatter={(value, name) => [formatTooltipValue(value, name), name]}
        />
        <Legend />
      </>
    )

    if (chartType === 'line') {
      return (
        <LineChart {...chartProps}>
          {commonElements}
          {config.series.map((seriesDef, index) => (
            <Line
              key={seriesDef.label}
              type='monotone'
              dataKey={seriesDef.label}
              stroke={colorRange[index] || colors.default}
              strokeWidth={2}
              dot={false}
            />
          ))}
        </LineChart>
      )
    }

    return (
      <BarChart {...chartProps}>
        {commonElements}
        {config.series.map((seriesDef, index) => (
          <Bar
            key={seriesDef.label}
            dataKey={seriesDef.label}
            stackId='history'
            fill={colorRange[index] || colors.default}
          />
        ))}
      </BarChart>
    )
  }

  return (
    <Card
      style={{ width: '100%' }}
      styles={{ body: { padding: '12px', ...styles } }}
    >
      <Flex gap='small' vertical>
        {!startDate && !endDate && (
          <Flex justify='space-between'>
            <Flex align='center' gap='5px'>
              <Popover
                content={customTimeRangeContent}
                trigger='hover'
                arrow={false}
                placement='bottomLeft'
                styles={{ body: { borderRadius: '22.5px' } }}
              >
                <Segmented
                  size='small'
                  options={[{ label: 'Custom', value: 'custom' }]}
                  value={timeRange}
                  onChange={setTimeRange}
                  disabled={loading}
                />
              </Popover>
            </Flex>

            <Flex gap='middle'>
              {loading == true && <LoadingOutlined />}
              <Segmented
                size='small'
                options={[
                  { label: '24hr', value: '24hrs' },
                  { label: '12hr', value: '12hrs' },
                  { label: '8hr', value: '8hrs' },
                  { label: '4hr', value: '4hrs' },
                  { label: '1hr', value: '1hrs' },
                  { label: '30m', value: '30mins' },
                  { label: '15m', value: '15mins' },
                  { label: '5m', value: '5mins' }
                ]}
                value={timeRange}
                onChange={setTimeRange}
                disabled={loading}
              />
            </Flex>
          </Flex>
        )}
        {chartRows.length > 0 && (
          <div style={{ width: '100%', height: `${height}px` }}>
            <ResponsiveContainer width='100%' height='100%'>
              {renderChart()}
            </ResponsiveContainer>
          </div>
        )}
        {loading == false && chartRows.length == 0 && (
          <Flex
            justify='center'
            align='center'
            style={{ height: `${height}px` }}
          >
            <MissingPlaceholder message='No data available.' />
          </Flex>
        )}
      </Flex>
    </Card>
  )
}

HistoryDisplay.propTypes = {
  history: PropTypes.arrayOf(PropTypes.object),
  objectType: PropTypes.oneOf([
    'filamentStock',
    'partStock',
    'productStock',
    'stockEvent'
  ]).isRequired,
  chartType: PropTypes.oneOf(['line', 'bar']),
  unit: PropTypes.string,
  startDate: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.instanceOf(Date)
  ]),
  loading: PropTypes.bool,
  endDate: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
  styles: PropTypes.object,
  height: PropTypes.oneOfType([PropTypes.number, PropTypes.string])
}

export default HistoryDisplay
