import { useCallback, useState } from 'react';

import CardContainer from '@design-system/CardContainer';
import BarChart from '@design-system/Charts/BarChart';
import Title from '@design-system/Title';
import { Box, Stack, useTheme } from '@mui/material';
import { IconBulb } from '@tabler/icons-react';
import {
  type ActiveElement,
  type ChartData,
  type ChartEvent,
  type ChartOptions,
} from 'chart.js';
import { isEmpty, range } from 'lodash';

import { type BaseDatum, type ScaleQuestionChartProps } from './types';
import { getColorFromType } from './utils';

// Helper to darken a hex color by a percentage (0-1)
const darkenColor = (hex: string, amount: number): string => {
  const r = Math.max(
    0,
    Math.floor(parseInt(hex.slice(1, 3), 16) * (1 - amount)),
  );
  const g = Math.max(
    0,
    Math.floor(parseInt(hex.slice(3, 5), 16) * (1 - amount)),
  );
  const b = Math.max(
    0,
    Math.floor(parseInt(hex.slice(5, 7), 16) * (1 - amount)),
  );
  return `rgb(${r}, ${g}, ${b})`;
};

const ScaleQuestionChart = <TDatum extends BaseDatum>({
  data,
  onSelectItem,
  helperText,
  noDataText,
}: ScaleQuestionChartProps<TDatum>) => {
  const theme = useTheme();
  const [selectedIndex, setSelectedIndex] = useState<number | null>(null);

  const hasData = data && !isEmpty(data);

  const handleClick = useCallback(
    (_event: ChartEvent, elements: ActiveElement[]) => {
      if (elements.length > 0 && hasData) {
        const dataIndex = elements[0].index;
        // Toggle selection: if clicking the same bar, deselect it
        setSelectedIndex(prev => (prev === dataIndex ? null : dataIndex));
        onSelectItem(data[dataIndex]);
      }
    },
    [data, hasData, onSelectItem],
  );

  const labels = hasData ? data.map(item => item.label) : range(1, 11);
  const values = hasData ? data.map(item => item.value) : [];

  // When a bar is selected, darken it
  const backgroundColors = hasData
    ? data.map((item, index) => {
        const baseColor = getColorFromType(item.type, theme);
        if (selectedIndex === null) {
          return baseColor;
        }
        return index === selectedIndex
          ? darkenColor(baseColor, 0.2)
          : baseColor;
      })
    : [];

  // Hover colors should also respect the selection state
  const hoverBackgroundColors = hasData
    ? data.map((item, index) => {
        const baseColor = getColorFromType(item.type, theme);
        if (selectedIndex === null) {
          return baseColor;
        }
        return index === selectedIndex
          ? darkenColor(baseColor, 0.2)
          : baseColor;
      })
    : [];

  const chartData: ChartData<'bar'> = {
    labels,
    datasets: [
      {
        data: values,
        backgroundColor: backgroundColors,
        hoverBackgroundColor: hoverBackgroundColors,
        borderRadius: 8,
        borderSkipped: 'bottom' as const,
      },
    ],
  };

  const options: ChartOptions<'bar'> = {
    responsive: true,
    maintainAspectRatio: false,
    animation: {
      duration: 300,
    },
    layout: {
      padding: {
        top: 10,
      },
    },
    plugins: {
      legend: {
        display: false,
      },
      tooltip: {
        enabled: hasData,
        backgroundColor: theme.palette.new.background.elements.inverted,
        titleFont: {
          family: theme.typography.fontFamily as string,
          size: theme.typography.fontSize as number,
          weight: 'normal',
        },
        bodyFont: {
          family: theme.typography.fontFamily as string,
          size: theme.typography.fontSize as number,
          weight: 'normal',
        },
        titleColor: theme.palette.new.text.neutral.inverted,
        bodyColor: theme.palette.new.text.neutral.inverted,
        padding: parseInt(theme.spacing(2), 10),
        cornerRadius: parseInt(
          theme.spacing(theme.shape.borderRadiusS as number),
          10,
        ),
        displayColors: false,
        callbacks: {
          title: () => '',
          label: context => {
            const index = context.dataIndex;
            if (hasData) {
              const item = data[index];
              return `${item.label}: ${item.value}%`;
            }
            return '';
          },
        },
      },
    },
    scales: {
      x: {
        grid: {
          display: false,
        },
        border: {
          display: false,
        },
        ticks: {
          color: theme.palette.new.text.neutral.lighter,
          font: {
            family: 'Roboto',
          },
        },
      },
      y: {
        min: 0,
        max: 100,
        grid: Object.assign(
          {
            lineWidth: 1,
            tickLength: 0,
          },
          { borderDash: [4, 4] },
        ),
        border: {
          display: false,
        },
        ticks: {
          color: theme.palette.new.text.neutral.lighter,
          font: {
            family: 'Roboto',
          },
          padding: 8,
        },
      },
    },
    onClick: handleClick,
    onHover: (event, elements) => {
      const canvas = event.native?.target as HTMLCanvasElement;
      if (canvas) {
        canvas.style.cursor = elements.length > 0 ? 'pointer' : 'default';
      }
    },
  };

  return (
    <CardContainer
      color="grey"
      fullWidth
    >
      <Box sx={{ position: 'relative', height: 400 }}>
        <BarChart
          type="bar"
          data={chartData}
          options={options}
        />
        {!hasData && noDataText && (
          <Box
            sx={{
              position: 'absolute',
              top: '50%',
              left: '50%',
              transform: 'translate(-50%, -50%)',
              color: theme.palette.new.text.neutral.lighter,
              fontFamily: 'Roboto',
              fontSize: theme.typography.fontSize,
            }}
          >
            {noDataText}
          </Box>
        )}
      </Box>
      {helperText && (
        <Stack
          sx={{ flexDirection: 'row', alignItems: 'center', gap: 1, mt: 1 }}
        >
          <IconBulb
            color={theme.palette.new.text.neutral.lighter}
            size={20}
          />
          <Title
            title={helperText}
            fontWeight="fontWeightRegular"
            slotProps={{
              title: {
                sx: {
                  color: theme.palette.new.text.neutral.lighter,
                },
              },
            }}
            variant="S"
          />
        </Stack>
      )}
    </CardContainer>
  );
};

export default ScaleQuestionChart;
