import { useAnimationFrame } from 'framer-motion';
import { useCallback, useEffect, useRef } from 'react';

import { useStores } from '@/app/(root)/AppProviders';

interface VisualizerOverlayProps {
  clipId: string;
  isPlaying: boolean;
  className?: string;
}

// This component will change later
export default function VisualizerOverlay({
  clipId,
  isPlaying,
  className = '',
}: VisualizerOverlayProps) {
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const { playbar } = useStores();

  const setupAnalyser = useCallback(() => {
    if (!playbar.audioElement || !playbar.sourceNode) {
      return null;
    }

    // Initialize analyser node if it doesn't exist
    if (!playbar.analyserNode) {
      try {
        const audioContext = playbar.sourceNode.context;
        playbar.analyserNode = audioContext.createAnalyser();
        playbar.analyserNode.fftSize = 256; // Lower for smoother bars
        playbar.analyserNode.smoothingTimeConstant = 0.8; // Smooth out the data

        // Connect the source to analyser and analyser to destination
        playbar.sourceNode.disconnect();
        playbar.sourceNode.connect(playbar.analyserNode);
        playbar.analyserNode.connect(audioContext.destination);
      } catch (error) {
        console.error('Error creating analyser node:', error);
        return null;
      }
    }

    const analyser = playbar.analyserNode;
    const bufferLength = analyser.frequencyBinCount;
    const dataArray = new Uint8Array(bufferLength);

    return { analyser, dataArray, bufferLength };
  }, [playbar.audioElement, playbar.sourceNode, playbar.analyserNode]);

  const drawVisualizer = useCallback(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;

    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    const analyserData = setupAnalyser();
    if (!analyserData) return;

    const { analyser, dataArray, bufferLength } = analyserData;

    // Get frequency data
    analyser.getByteFrequencyData(dataArray);

    // Clear canvas
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // Set up drawing properties
    const barCount = 32; // Number of bars to display
    const barWidth = canvas.width / barCount;
    const maxBarHeight = canvas.height * 0.2; // Short bars

    // Create gradient from top to bottom
    const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
    gradient.addColorStop(0, 'rgba(253, 66, 156, 0.6)'); // More visible pink
    gradient.addColorStop(0.5, 'rgba(253, 66, 156, 0.45)');
    gradient.addColorStop(1, 'rgba(253, 66, 156, 0.25)');

    ctx.fillStyle = gradient;

    // Draw bars from top
    for (let i = 0; i < barCount; i++) {
      // Map to frequency data (focus on lower frequencies for music)
      const dataIndex = Math.floor((i / barCount) * (bufferLength * 0.7));
      const barHeight = Math.max(
        2,
        (dataArray[dataIndex] / 255) * maxBarHeight
      );

      const x = i * barWidth;
      const y = 0; // Start from top

      // Draw rounded rectangle bar
      ctx.beginPath();
      ctx.roundRect(x + 1, y, barWidth - 2, barHeight, 2);
      ctx.fill();
    }

    // Add subtle glow effect
    ctx.shadowColor = 'rgba(253, 66, 156, 0.4)';
    ctx.shadowBlur = 10;

    // Draw again for glow
    ctx.fillStyle = 'rgba(253, 66, 156, 0.3)';
    for (let i = 0; i < barCount; i++) {
      const dataIndex = Math.floor((i / barCount) * (bufferLength * 0.7));
      const barHeight = Math.max(
        2,
        (dataArray[dataIndex] / 255) * maxBarHeight
      );

      const x = i * barWidth;
      const y = 0; // Start from top

      ctx.beginPath();
      ctx.roundRect(x + 1, y, barWidth - 2, barHeight, 2);
      ctx.fill();
    }

    // Reset shadow
    ctx.shadowColor = 'transparent';
    ctx.shadowBlur = 0;
  }, [setupAnalyser]);

  // Animation loop
  useAnimationFrame(
    useCallback(() => {
      const isCurrentClipPlaying =
        isPlaying && playbar.clip?.id === clipId && playbar.isPlaying;

      if (isCurrentClipPlaying) {
        drawVisualizer();
      } else {
        // Clear canvas when not playing
        const canvas = canvasRef.current;
        if (canvas) {
          const ctx = canvas.getContext('2d');
          if (ctx) {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
          }
        }
      }
    }, [
      drawVisualizer,
      isPlaying,
      clipId,
      playbar,
      playbar.clip?.id,
      playbar.isPlaying,
    ])
  );

  // Setup canvas on mount and when container resizes
  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;

    const container = canvas.parentElement;
    if (!container) return;

    const updateCanvasSize = () => {
      canvas.width = container.clientWidth * window.devicePixelRatio;
      canvas.height = container.clientHeight * window.devicePixelRatio;
      canvas.style.width = `${container.clientWidth}px`;
      canvas.style.height = `${container.clientHeight}px`;

      const ctx = canvas.getContext('2d');
      if (ctx) {
        ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
      }
    };

    updateCanvasSize();

    const resizeObserver = new ResizeObserver(updateCanvasSize);
    resizeObserver.observe(container);

    return () => {
      resizeObserver.disconnect();
    };
  }, []);

  return (
    <canvas
      ref={canvasRef}
      className={`pointer-events-none absolute inset-0 h-full w-full ${className}`}
      style={{
        mixBlendMode: 'screen', // Blend mode for better overlay effect
      }}
    />
  );
}
