using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// Responsible for generating and rendering an audio waveform onto a UI Image component.
/// </summary>
public class WaveformRenderer : MonoBehaviour
{
    [Header("References")]

    [Tooltip("UI Image component where the waveform will be displayed.")]
    [SerializeField] private Image waveformImage;

    [Tooltip("Audio clip from which the waveform is generated.")]
    [SerializeField] private AudioClip audioClip;

    [Header("Waveform Settings")]

    [Tooltip("Color used to draw the waveform.")]
    [SerializeField] private Color waveformColor = Color.green;

    /// <summary>
    /// Public method to generate and render the waveform.
    /// Make sure 'audioClip' and 'waveformImage' are assigned before calling this.
    /// </summary>
    public void RenderWaveform()
    {
        if (audioClip == null)
        {
            Debug.LogError("[WaveformRenderer] AudioClip reference is not assigned.");
            return;
        }

        if (waveformImage == null)
        {
            Debug.LogError("[WaveformRenderer] Waveform Image reference is not assigned.");
            return;
        }

        // Retrieve RectTransform associated with the waveform image UI element.
        RectTransform rectTransform = waveformImage.rectTransform;

        // Calculate the absolute pixel size of the RectTransform, accounting for scaling.
        Vector2 scaledSize = new Vector2(
            rectTransform.rect.width * rectTransform.lossyScale.x,
            rectTransform.rect.height * rectTransform.lossyScale.y);

        int width = Mathf.Max(1, Mathf.RoundToInt(scaledSize.x));
        int height = Mathf.Max(1, Mathf.RoundToInt(scaledSize.y));

        // Generate the waveform texture based on the audio clip and UI size.
        Texture2D waveformTexture = GenerateWaveformTexture(audioClip, width, height, waveformColor);

        // Apply the generated texture to the UI Image component as a sprite.
        ApplyTextureToImage(waveformTexture);
    }

    /// <summary>
    /// Generates a Texture2D representing the waveform of the provided AudioClip.
    /// </summary>
    /// <param name="clip">The audio clip to process.</param>
    /// <param name="width">Width of the output texture in pixels.</param>
    /// <param name="height">Height of the output texture in pixels.</param>
    /// <param name="color">Color used to draw the waveform.</param>
    /// <returns>A Texture2D with the rendered waveform.</returns>
    private Texture2D GenerateWaveformTexture(AudioClip clip, int width, int height, Color color)
    {
        // Create a new transparent texture
        Texture2D texture = new Texture2D(width, height, TextureFormat.RGBA32, false);

        // Clear the texture with a fully transparent color.
        Color32 transparent = new Color32(0, 0, 0, 0);
        Color32[] clearPixels = new Color32[width * height];
        for (int i = 0; i < clearPixels.Length; i++)
            clearPixels[i] = transparent;
        texture.SetPixels32(clearPixels);

        // Retrieve all audio samples (interleaved if multiple channels).
        float[] samples = new float[clip.samples * clip.channels];
        clip.GetData(samples, 0);

        int channels = clip.channels;
        int midHeight = height / 2;
        
        // Determine how many samples correspond to a single horizontal pixel.
        int samplesPerPixel = Mathf.Max((samples.Length / channels) / width, 1);

        // Iterate over every horizontal pixel column to calculate waveform amplitude.
        for (int x = 0; x < width; x++)
        {
            int sampleStartIndex = x * samplesPerPixel * channels;
            int sampleEndIndex = Mathf.Min(sampleStartIndex + samplesPerPixel * channels, samples.Length);

            float maxAmplitude = 0f;

            // Find the maximum absolute amplitude in the range of samples corresponding to this pixel.
            for (int i = sampleStartIndex; i < sampleEndIndex; i += channels)
            {
                float amplitude = Mathf.Abs(samples[i]);
                if (amplitude > maxAmplitude)
                    maxAmplitude = amplitude;
            }

            // Calculate vertical amplitude in pixels based on max amplitude and half texture height.
            int amplitudeHeight = Mathf.RoundToInt(maxAmplitude * midHeight);

            // Draw a vertical line centered vertically, corresponding to the amplitude.
            int startY = Mathf.Clamp(midHeight - amplitudeHeight, 0, height - 1);
            int endY = Mathf.Clamp(midHeight + amplitudeHeight, 0, height - 1);

            for (int y = startY; y <= endY; y++)
            {
                texture.SetPixel(x, y, color);
            }
        }

        // Apply changes to the texture.
        texture.Apply();

        return texture;
    }

    /// <summary>
    /// Creates a new Sprite from the generated texture and assigns it to the Image component.
    /// </summary>
    /// <param name="texture">The texture containing the waveform.</param>
    private void ApplyTextureToImage(Texture2D texture)
    {
        // Create a new Sprite centered on pivot (0.5,0.5) with full texture rect.
        Sprite waveformSprite = Sprite.Create(
            texture,
            new Rect(0, 0, texture.width, texture.height),
            new Vector2(0.5f, 0.5f));

        // Assign the sprite to the Image component and reset color & aspect settings.
        waveformImage.sprite = waveformSprite;
        waveformImage.color = Color.white;
        waveformImage.preserveAspect = true;
    }
}

give my script a wave style selection dropdown in its inspector that will allow me to pick from render styles of Normal, Choppy, Blocks and make those options a reality, provide script in full ty