import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import IframelyEmbed from './IframelyEmbed';

const EMBED_URL = 'https://bsky.app/profile/example.bsky.social/post/abc123';
const EMBED_HTML = `<div class="iframely-embed"><div class="iframely-responsive" style="padding-bottom: 100%;"><a href="${EMBED_URL}" target="_blank"></a></div></div>`;
const EMBED_JS_SRC = 'https://cdn.iframe.ly/embed.js';

function successFetch(html: string) {
  return vi.spyOn(globalThis, 'fetch').mockResolvedValue(
    new Response(JSON.stringify({ html }), {
      status: 200,
      headers: { 'Content-Type': 'application/json' },
    }),
  );
}

beforeEach(() => {
  vi.restoreAllMocks();
  vi.stubEnv('VITE_API_URL', 'http://localhost:3000');
  // Clean up any embed.js script tags injected by previous tests.
  document.querySelectorAll(`script[src="${EMBED_JS_SRC}"]`).forEach((el) => el.remove());
});

afterEach(() => {
  document.querySelectorAll(`script[src="${EMBED_JS_SRC}"]`).forEach((el) => el.remove());
});

describe('IframelyEmbed', () => {
  it('shows loading state initially', () => {
    vi.spyOn(globalThis, 'fetch').mockResolvedValue(new Response('{}', { status: 200 }));
    render(<IframelyEmbed url={EMBED_URL} />);
    expect(screen.getByText('Loading embed...')).toBeInTheDocument();
  });

  it('renders embed HTML after successful fetch', async () => {
    successFetch(EMBED_HTML);
    const { container } = render(<IframelyEmbed url={EMBED_URL} />);
    await waitFor(() => expect(container.querySelector('.iframely-embed')).not.toBeNull());
    expect(container.querySelector('.iframely-responsive')).not.toBeNull();
  });

  it('injects embed.js into document.head after HTML loads', async () => {
    successFetch(EMBED_HTML);
    render(<IframelyEmbed url={EMBED_URL} />);
    await waitFor(() =>
      expect(document.querySelector(`script[src="${EMBED_JS_SRC}"]`)).not.toBeNull(),
    );
    const script = document.querySelector<HTMLScriptElement>(`script[src="${EMBED_JS_SRC}"]`)!;
    expect(script.integrity).toBe('sha256-3GwLJcK+mlckENNer3dPxN7pSjeNqIRkurShyMXvtsw=');
    expect(script.crossOrigin).toBe('anonymous');
    expect(script.async).toBe(true);
  });

  it('does not inject embed.js twice when multiple embeds load', async () => {
    successFetch(EMBED_HTML);
    render(<IframelyEmbed url={EMBED_URL} />);
    render(<IframelyEmbed url="https://bsky.app/profile/other.bsky.social/post/xyz" />);
    await waitFor(() =>
      expect(document.querySelector(`script[src="${EMBED_JS_SRC}"]`)).not.toBeNull(),
    );
    const scripts = document.querySelectorAll(`script[src="${EMBED_JS_SRC}"]`);
    expect(scripts).toHaveLength(1);
  });

  it('calls iframely.load() when embed.js is already present', async () => {
    // Simulate embed.js already loaded from a prior render.
    const existing = document.createElement('script');
    existing.src = EMBED_JS_SRC;
    document.head.appendChild(existing);

    const load = vi.fn();
    (window as { iframely?: { load(): void } }).iframely = { load };

    successFetch(EMBED_HTML);
    render(<IframelyEmbed url={EMBED_URL} />);
    await waitFor(() => expect(load).toHaveBeenCalled());

    delete (window as { iframely?: unknown }).iframely;
  });

  it('does not inject embed.js when fetch fails', async () => {
    vi.spyOn(globalThis, 'fetch').mockRejectedValue(new Error('network error'));
    render(<IframelyEmbed url={EMBED_URL} />);
    await waitFor(() => expect(screen.getByRole('link', { name: EMBED_URL })).toBeInTheDocument());
    expect(document.querySelector(`script[src="${EMBED_JS_SRC}"]`)).toBeNull();
  });

  it('shows fallback link on non-ok response', async () => {
    vi.spyOn(globalThis, 'fetch').mockResolvedValue(new Response('{}', { status: 500 }));
    render(<IframelyEmbed url={EMBED_URL} />);
    await waitFor(() => expect(screen.getByRole('link', { name: EMBED_URL })).toBeInTheDocument());
  });
});
