/**
 * @file AudioPlayer.test.tsx
 * @description Tests for the AudioPlayer component that provides inline TTS audio playback
 */

import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { AudioPlayer } from "./AudioPlayer";

// Mock HTMLAudioElement
class MockAudio {
  src = "";
  currentTime = 0;
  duration = 60;
  paused = true;
  playbackRate = 1;
  volume = 1;
  onended: (() => void) | null = null;
  ontimeupdate: (() => void) | null = null;
  onloadedmetadata: (() => void) | null = null;
  onerror: ((e: unknown) => void) | null = null;

  play(): Promise<void> {
    this.paused = false;
    return Promise.resolve();
  }

  pause(): void {
    this.paused = true;
  }

  addEventListener(event: string, handler: () => void): void {
    if (event === "ended") this.onended = handler;
    if (event === "timeupdate") this.ontimeupdate = handler;
    if (event === "loadedmetadata") this.onloadedmetadata = handler;
    if (event === "error") this.onerror = handler;
  }

  removeEventListener(): void {
    // no-op for tests
  }
}

vi.stubGlobal("Audio", MockAudio);

describe("AudioPlayer", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe("rendering", () => {
    it("should render play button", () => {
      render(<AudioPlayer src="blob:test-audio" />);

      const playButton = screen.getByRole("button", { name: "Play audio" });
      expect(playButton).toBeInTheDocument();
    });

    it("should render download button", () => {
      render(<AudioPlayer src="blob:test-audio" />);

      const downloadButton = screen.getByRole("button", { name: /download/i });
      expect(downloadButton).toBeInTheDocument();
    });

    it("should render time display showing 0:00", () => {
      render(<AudioPlayer src="blob:test-audio" />);

      expect(screen.getByText("0:00")).toBeInTheDocument();
    });

    it("should render speed control", () => {
      render(<AudioPlayer src="blob:test-audio" />);

      const speedButton = screen.getByRole("button", { name: "Playback speed" });
      expect(speedButton).toBeInTheDocument();
    });

    it("should render progress bar", () => {
      render(<AudioPlayer src="blob:test-audio" />);

      const progressBar = screen.getByRole("progressbar");
      expect(progressBar).toBeInTheDocument();
    });

    it("should not render when src is null", () => {
      const { container } = render(<AudioPlayer src={null} />);

      expect(container.firstChild).toBeNull();
    });
  });

  describe("play/pause", () => {
    it("should toggle to pause button when playing", async () => {
      const user = userEvent.setup();
      render(<AudioPlayer src="blob:test-audio" />);

      const playButton = screen.getByRole("button", { name: "Play audio" });
      await user.click(playButton);

      expect(screen.getByRole("button", { name: "Pause audio" })).toBeInTheDocument();
    });
  });

  describe("speed control", () => {
    it("should cycle through speed options on click", async () => {
      const user = userEvent.setup();
      render(<AudioPlayer src="blob:test-audio" />);

      const speedButton = screen.getByRole("button", { name: "Playback speed" });

      // Default should be 1x
      expect(speedButton).toHaveTextContent("1x");

      // Click to go to 1.5x
      await user.click(speedButton);
      expect(speedButton).toHaveTextContent("1.5x");

      // Click to go to 2x
      await user.click(speedButton);
      expect(speedButton).toHaveTextContent("2x");

      // Click to go to 0.5x
      await user.click(speedButton);
      expect(speedButton).toHaveTextContent("0.5x");

      // Click to go back to 1x
      await user.click(speedButton);
      expect(speedButton).toHaveTextContent("1x");
    });
  });

  describe("accessibility", () => {
    it("should have proper aria labels on controls", () => {
      render(<AudioPlayer src="blob:test-audio" />);

      expect(screen.getByRole("button", { name: "Play audio" })).toBeInTheDocument();
      expect(screen.getByRole("button", { name: /download/i })).toBeInTheDocument();
      expect(screen.getByRole("button", { name: "Playback speed" })).toBeInTheDocument();
      expect(screen.getByRole("progressbar")).toHaveAttribute("aria-label");
    });

    it("should have region role on the player container", () => {
      render(<AudioPlayer src="blob:test-audio" />);

      expect(screen.getByRole("region", { name: /audio player/i })).toBeInTheDocument();
    });
  });

  describe("design", () => {
    it("should not use aggressive red colors", () => {
      const { container } = render(<AudioPlayer src="blob:test-audio" />);

      const allElements = container.querySelectorAll("*");
      allElements.forEach((el) => {
        const className = el.className;
        if (typeof className === "string") {
          expect(className).not.toMatch(/bg-red-|text-red-|border-red-/);
        }
      });
    });
  });

  describe("callbacks", () => {
    it("should call onPlayStateChange when play state changes", async () => {
      const onPlayStateChange = vi.fn();
      const user = userEvent.setup();

      render(<AudioPlayer src="blob:test-audio" onPlayStateChange={onPlayStateChange} />);

      const playButton = screen.getByRole("button", { name: "Play audio" });
      await user.click(playButton);

      expect(onPlayStateChange).toHaveBeenCalledWith(true);
    });
  });
});
