import React, { useMemo } from 'react';
import { Platform } from 'react-native';
import { ForeignObject, G } from 'react-native-svg';
import { useTheme } from '../../../theme';
import Box from '../../Box';
import type { AxisCoordinates, YAxisConfig } from '../types';
import AxisLabel from './AxisLabel';
import useGenerateTicks from './hooks/useGenerateTicks';
import useScaleLinearY from './hooks/useScaleLinearY';

export type YAxisProps = {
  yAxisConfig: YAxisConfig & { minValue?: number };
  coordinates: AxisCoordinates;
};

const YAxis = ({ yAxisConfig, coordinates }: YAxisProps) => {
  const theme = useTheme();
  const { maxValue, minValue, step, labels } = yAxisConfig;
  const { yStart, yEnd, xEnd, xStart } = coordinates;
  const { yAxisDefaultTextWidth } = theme.__hd__.chart.sizes;

  // Whether to use custom labels instead of generated ticks
  const shouldUseCustomLabels = labels && labels.length > 0;

  const maxValueOrZero = maxValue || 0;
  const minValueOrZero = minValue || 0;

  // Adjust scaleY to fit within the chart area, leaving space for the bottom space for the X axis
  const scaleY = useScaleLinearY({
    maxValue: maxValueOrZero,
    minValue: minValueOrZero,
    yStart,
    yEnd,
  });

  // Generate ticks, including maxValue if needed
  const ticks = useGenerateTicks({
    maxValue: maxValueOrZero,
    minValue: minValueOrZero,
    step,
  });

  const data = useMemo(
    () =>
      ticks.map((tick, index) => {
        if (shouldUseCustomLabels) {
          return { tick, label: labels[index] };
        }
        return {
          tick,
          label: Number.isInteger(tick)
            ? tick.toString()
            : Number(tick).toFixed(2),
        };
      }),
    [ticks, shouldUseCustomLabels, labels]
  );

  return (
    <G>
      {data.map(({ label, tick }) => (
        <G key={label}>
          {/*
            Cross-platform Y-axis label rendering:
            - On web: Use ForeignObject to allow HTML/CSS styling and ellipsis with Typography.Label.
              The x position is set to xStart - yAxisDefaultTextWidth to right-align the label box.
            - On native: Use Box with absolute positioning and Typography.Label for compatibility.
              The transform centers the label vertically.
          */}
          {Platform.OS === 'web' ? (
            <ForeignObject
              x={xStart - yAxisDefaultTextWidth}
              y={scaleY(tick) - theme.__hd__.typography.lineHeights.label / 2}
              width={yAxisDefaultTextWidth}
              height={theme.__hd__.typography.lineHeights.label}
            >
              <AxisLabel label={label} />
            </ForeignObject>
          ) : (
            <Box
              testID={`y-axis-label-${tick}-container`}
              style={{
                position: 'absolute',
                maxWidth: yAxisDefaultTextWidth,
                top: scaleY(tick),
                transform: [
                  {
                    translateY:
                      0 - theme.__hd__.typography.lineHeights.label / 2, // center label vertically
                  },
                ],
                right: xEnd - yAxisDefaultTextWidth,
              }}
            >
              <AxisLabel label={label} />
            </Box>
          )}
        </G>
      ))}
    </G>
  );
};

export default YAxis;
