import { useTranslation } from 'react-i18next';
import { formatValue } from '../../lib/format';
import { ts } from '../../i18n/server';
import {
  DENSITY_GRADIENT,
  DENSITY_GRADIENT_DARK,
  getEnumPaletteForFeature,
  getFeatureGradient,
} from '../../lib/consts';
import { gradientToCss } from '../../lib/utils';
import { CloseIcon } from '../ui/icons/CloseIcon';
import { TickerValue } from '../ui/TickerValue';

function ResetScaleIcon({ className = 'w-4 h-4' }: { className?: string }) {
  return (
    <svg
      className={className}
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth={2}
    >
      <path strokeLinecap="round" strokeLinejoin="round" d="M3 12a9 9 0 0115.13-6.36L21 8" />
      <path strokeLinecap="round" strokeLinejoin="round" d="M21 3v5h-5" />
      <path strokeLinecap="round" strokeLinejoin="round" d="M21 12a9 9 0 01-15.13 6.36L3 16" />
      <path strokeLinecap="round" strokeLinejoin="round" d="M3 21v-5h5" />
    </svg>
  );
}

function requireFeatureName(featureName: string | undefined): string {
  if (!featureName) {
    throw new Error('Enum legend requested without a feature name');
  }
  return featureName;
}

function requireEnumPalette(
  palette: [number, number, number][] | null
): [number, number, number][] {
  if (!palette) {
    throw new Error('Enum legend requested without a palette');
  }
  return palette;
}

function EnumSwatches({
  values,
  palette,
}: {
  values: string[];
  palette: [number, number, number][];
}) {
  return (
    <div className="flex flex-col gap-1">
      {values.map((label, i) => {
        const color = palette[i % palette.length];
        return (
          <div key={label} className="flex items-center gap-1.5">
            <div
              className="w-3 h-3 rounded-sm shrink-0"
              style={{ backgroundColor: `rgb(${color[0]},${color[1]},${color[2]})` }}
            />
            <span className="text-warm-600 dark:text-warm-300 truncate">{ts(label)}</span>
          </div>
        );
      })}
    </div>
  );
}

function InlineEnumSwatches({
  values,
  palette,
}: {
  values: string[];
  palette: [number, number, number][];
}) {
  return (
    <div className="flex items-center gap-2 flex-1 min-w-[40%] flex-wrap">
      {values.map((label, i) => {
        const color = palette[i % palette.length];
        return (
          <div key={label} className="flex items-center gap-1">
            <div
              className="w-2.5 h-2.5 rounded-sm shrink-0"
              style={{ backgroundColor: `rgb(${color[0]},${color[1]},${color[2]})` }}
            />
            <span className="text-warm-500 dark:text-warm-400 whitespace-nowrap text-[11px]">
              {ts(label)}
            </span>
          </div>
        );
      })}
    </div>
  );
}

export default function MapLegend({
  featureLabel,
  range,
  showCancel,
  onCancel,
  mode,
  enumValues,
  featureName,
  theme = 'light',
  inline = false,
  suffix,
  raw,
  totalCount,
  onResetScale,
  resetScaleDisabled = false,
}: {
  featureLabel: string;
  range: [number, number];
  showCancel: boolean;
  onCancel: () => void;
  mode: 'feature' | 'density';
  enumValues?: string[];
  featureName?: string;
  theme?: 'light' | 'dark';
  inline?: boolean;
  suffix?: string;
  raw?: boolean;
  totalCount?: number;
  onResetScale?: () => void;
  resetScaleDisabled?: boolean;
}) {
  const { t } = useTranslation();
  const isEnum = enumValues && enumValues.length > 0;
  const showResetScale = Boolean(onResetScale) && !isEnum;
  const enumPalette = isEnum
    ? getEnumPaletteForFeature(requireFeatureName(featureName), enumValues)
    : null;
  const densityGradient = theme === 'dark' ? DENSITY_GRADIENT_DARK : DENSITY_GRADIENT;
  const gradientStyle =
    mode === 'density'
      ? gradientToCss(densityGradient)
      : gradientToCss(getFeatureGradient(featureName));

  const fmt = raw ? { raw: true } : undefined;

  const rangeMin =
    mode === 'density' ? (
      <TickerValue text={formatValue(range[0])} />
    ) : isEnum ? null : (
      <TickerValue text={formatValue(range[0], fmt) + (suffix || '')} />
    );

  const rangeMax =
    mode === 'density' ? (
      <TickerValue text={formatValue(range[1])} />
    ) : isEnum ? null : (
      <TickerValue text={formatValue(range[1], fmt) + (suffix || '')} />
    );

  if (inline) {
    return (
      <div className="bg-warm-100 dark:bg-warm-800 text-warm-700 dark:text-warm-200 px-3 py-1.5 text-xs border-b border-warm-200 dark:border-warm-700 flex items-center gap-2">
        <span className="font-semibold text-xs text-warm-800 dark:text-warm-200 truncate">
          {featureLabel}
        </span>
        {showResetScale && (
          <button
            onClick={onResetScale}
            disabled={resetScaleDisabled}
            className="text-warm-400 hover:text-warm-700 dark:hover:text-warm-300 disabled:opacity-40 disabled:hover:text-warm-400 dark:disabled:hover:text-warm-400 shrink-0"
            title={t('mapLegend.resetColourScale')}
            aria-label={t('mapLegend.resetColourScale')}
          >
            <ResetScaleIcon className="w-3.5 h-3.5" />
          </button>
        )}
        {showCancel && (
          <button
            onClick={onCancel}
            className="text-warm-400 hover:text-warm-700 dark:hover:text-warm-300 shrink-0"
            title={t('mapLegend.clearColourView')}
            aria-label={t('mapLegend.clearColourView')}
          >
            <CloseIcon className="w-3.5 h-3.5" />
          </button>
        )}
        {isEnum ? (
          <InlineEnumSwatches values={enumValues} palette={requireEnumPalette(enumPalette)} />
        ) : (
          <div className="flex items-center gap-1.5 flex-1 min-w-[40%] text-warm-500 dark:text-warm-400">
            {rangeMin}
            <div
              className="h-2.5 rounded flex-1 min-w-[40px]"
              style={{ background: gradientStyle }}
            />
            {rangeMax}
          </div>
        )}
      </div>
    );
  }

  return (
    <div className="bg-white dark:bg-navy-800 dark:text-white rounded shadow-lg p-3 text-xs min-w-[300px] pointer-events-auto">
      <div className="flex items-center justify-between mb-2">
        <span className="font-semibold text-sm dark:text-white min-w-0 truncate">
          {featureLabel}
        </span>
        {(showResetScale || showCancel) && (
          <div className="flex items-center gap-1.5 ml-2 shrink-0">
            {showResetScale && (
              <button
                onClick={onResetScale}
                disabled={resetScaleDisabled}
                className="text-warm-400 hover:text-warm-700 dark:hover:text-warm-300 disabled:opacity-40 disabled:hover:text-warm-400 dark:disabled:hover:text-warm-400"
                title={t('mapLegend.resetColourScale')}
                aria-label={t('mapLegend.resetColourScale')}
              >
                <ResetScaleIcon className="w-4 h-4" />
              </button>
            )}
            {showCancel && (
              <button
                onClick={onCancel}
                className="text-warm-400 hover:text-warm-700 dark:hover:text-warm-300"
                title={t('mapLegend.clearColourView')}
                aria-label={t('mapLegend.clearColourView')}
              >
                <CloseIcon className="w-4 h-4" />
              </button>
            )}
          </div>
        )}
      </div>
      {isEnum ? (
        <EnumSwatches values={enumValues} palette={requireEnumPalette(enumPalette)} />
      ) : (
        <>
          <div className="h-3 rounded" style={{ background: gradientStyle }} />
          <div className="flex justify-between mt-1 text-warm-600 dark:text-warm-200">
            {rangeMin}
            {rangeMax}
          </div>
        </>
      )}
      {totalCount != null && (
        <div className="mt-2 pt-2 border-t border-warm-200 dark:border-warm-700 text-warm-600 dark:text-warm-300 flex items-center justify-between">
          <span>{t('common.total')}</span>
          <span className="font-semibold text-navy-950 dark:text-warm-100">
            <TickerValue text={formatValue(totalCount)} />
          </span>
        </div>
      )}
    </div>
  );
}
