import { afterEach, describe, expect, test, vi } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/svelte';
import { mockQuery } from '../../test-utils/query';

const invalidateMock = vi.fn();
vi.mock('@tanstack/svelte-query', async (orig) => {
  const actual = (await orig()) as Record<string, unknown>;
  return { ...actual, useQueryClient: () => ({ invalidateQueries: invalidateMock }) };
});

vi.mock('$lib/api/suggestions', () => ({
  createSuggestionsQuery: vi.fn()
}));

vi.mock('$lib/api/requests', () => ({
  createRequest: vi.fn().mockResolvedValue({})
}));

import SuggestionFeed from './SuggestionFeed.svelte';
import { createSuggestionsQuery } from '$lib/api/suggestions';
import { createRequest } from '$lib/api/requests';
import type { ArtistSuggestion } from '$lib/api/types';

const oneSeed: ArtistSuggestion = {
  mbid: 'mb1',
  name: 'Outsider',
  score: 1.0,
  attribution: [
    { artist_id: 'a1', name: 'Seed', contribution: 0.9, is_liked: true, play_count: 0 }
  ]
};

const twoSeeds: ArtistSuggestion = {
  mbid: 'mb2',
  name: 'Outsider Two',
  score: 2.0,
  attribution: [
    { artist_id: 'a1', name: 'A', contribution: 0.8, is_liked: true, play_count: 0 },
    { artist_id: 'a2', name: 'B', contribution: 0.5, is_liked: false, play_count: 3 }
  ]
};

const threeSeeds: ArtistSuggestion = {
  mbid: 'mb3',
  name: 'Outsider Three',
  score: 3.0,
  attribution: [
    { artist_id: 'a1', name: 'X', contribution: 0.9, is_liked: true, play_count: 0 },
    { artist_id: 'a2', name: 'Y', contribution: 0.6, is_liked: false, play_count: 5 },
    { artist_id: 'a3', name: 'Z', contribution: 0.3, is_liked: false, play_count: 1 }
  ]
};

afterEach(() => vi.clearAllMocks());

describe('SuggestionFeed', () => {
  test('renders one card per suggestion', () => {
    (createSuggestionsQuery as ReturnType<typeof vi.fn>).mockReturnValue(
      mockQuery({ data: [oneSeed, twoSeeds] })
    );
    render(SuggestionFeed);
    expect(screen.getByText('Outsider')).toBeInTheDocument();
    expect(screen.getByText('Outsider Two')).toBeInTheDocument();
  });

  test('attribution copy: 1 seed → "Because you liked X."', () => {
    (createSuggestionsQuery as ReturnType<typeof vi.fn>).mockReturnValue(
      mockQuery({ data: [oneSeed] })
    );
    render(SuggestionFeed);
    expect(screen.getByText(/because you liked seed\./i)).toBeInTheDocument();
  });

  test('attribution copy: 2 seeds → "Because you liked A and played B."', () => {
    (createSuggestionsQuery as ReturnType<typeof vi.fn>).mockReturnValue(
      mockQuery({ data: [twoSeeds] })
    );
    render(SuggestionFeed);
    expect(screen.getByText(/because you liked a and played b\./i)).toBeInTheDocument();
  });

  test('attribution copy: 3 seeds → Oxford comma', () => {
    (createSuggestionsQuery as ReturnType<typeof vi.fn>).mockReturnValue(
      mockQuery({ data: [threeSeeds] })
    );
    render(SuggestionFeed);
    expect(screen.getByText(/because you liked x, played y, and played z\./i)).toBeInTheDocument();
  });

  test('Request button calls createRequest with artist-kind body', async () => {
    (createSuggestionsQuery as ReturnType<typeof vi.fn>).mockReturnValue(
      mockQuery({ data: [oneSeed] })
    );
    render(SuggestionFeed);
    await fireEvent.click(screen.getByRole('button', { name: /request outsider/i }));
    expect(createRequest).toHaveBeenCalledWith({
      kind: 'artist',
      lidarr_artist_mbid: 'mb1',
      artist_name: 'Outsider'
    });
    expect(invalidateMock).toHaveBeenCalled();
  });

  test('empty state when data is []', () => {
    (createSuggestionsQuery as ReturnType<typeof vi.fn>).mockReturnValue(mockQuery({ data: [] }));
    render(SuggestionFeed);
    expect(screen.getByText(/listen to something or like an artist/i)).toBeInTheDocument();
  });
});
