import { ref, computed } from 'vue';

export interface ZoomOptionsStep {
  min: number;
  max: number;
  step: number;
  initial?: number;
}

export interface ZoomOptionsAllowed {
  allowedValues: number[];
  initial?: number;
}

export type ZoomOptions = ZoomOptionsStep | ZoomOptionsAllowed;

function isStepOptions(options: ZoomOptions): options is ZoomOptionsStep {
  return 'step' in options;
}

export function useZoom(options: ZoomOptions) {
  const initial = options.initial ?? (isStepOptions(options) ? 1 : (options.allowedValues[1] ?? options.allowedValues[0]));
  const zoom = ref(initial);

  const zoomPercent = computed(() => Math.round(zoom.value * 100));

  const increase = () => {
    if (isStepOptions(options)) {
      zoom.value = Math.min(options.max, zoom.value + options.step);
    } else {
      const currentIndex = options.allowedValues.indexOf(zoom.value);
      if (currentIndex < options.allowedValues.length - 1) {
        zoom.value = options.allowedValues[currentIndex + 1];
      } else if (currentIndex === -1) {
        // Find the nearest higher value
        const higher = options.allowedValues.find(v => v > zoom.value);
        if (higher !== undefined) {
          zoom.value = higher;
        }
      }
    }
  };

  const decrease = () => {
    if (isStepOptions(options)) {
      zoom.value = Math.max(options.min, zoom.value - options.step);
    } else {
      const currentIndex = options.allowedValues.indexOf(zoom.value);
      if (currentIndex > 0) {
        zoom.value = options.allowedValues[currentIndex - 1];
      } else if (currentIndex === -1) {
        // Find the nearest lower value
        const lower = [...options.allowedValues].reverse().find(v => v < zoom.value);
        if (lower !== undefined) {
          zoom.value = lower;
        }
      }
    }
  };

  const reset = () => {
    zoom.value = initial;
  };

  const setZoom = (value: number) => {
    if (isStepOptions(options)) {
      zoom.value = Math.max(options.min, Math.min(options.max, value));
    } else {
      // Snap to nearest allowed value
      const nearest = options.allowedValues.reduce((prev, curr) => (Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev));
      zoom.value = nearest;
    }
  };

  return {
    zoom,
    zoomPercent,
    increase,
    decrease,
    reset,
    setZoom,
  };
}
