import { afterEach, describe, expect, test, vi } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/svelte';
import FlagPopover from './FlagPopover.svelte';
import { makeTrack } from '$test-utils/fixtures/track';

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/quarantine', () => ({
  flagTrack: vi.fn().mockResolvedValue({ track_id: 't1', reason: 'bad_rip' })
}));

import { flagTrack } from '$lib/api/quarantine';

const track = makeTrack();

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

describe('FlagPopover', () => {
  test('default reason is bad_rip; button reads "Flag" when not initialReason', () => {
    render(FlagPopover, { props: { track, onClose: vi.fn() } });
    const select = screen.getByRole('combobox') as HTMLSelectElement;
    expect(select.value).toBe('bad_rip');
    expect(screen.getByRole('button', { name: /^flag$/i })).toBeInTheDocument();
  });

  test('pre-fills reason and notes when initial values are provided; button reads "Update flag"', () => {
    render(FlagPopover, {
      props: {
        track,
        onClose: vi.fn(),
        initialReason: 'wrong_tags',
        initialNotes: 'wrong artist'
      }
    });
    const select = screen.getByRole('combobox') as HTMLSelectElement;
    expect(select.value).toBe('wrong_tags');
    const textarea = screen.getByPlaceholderText(/what's wrong/i) as HTMLTextAreaElement;
    expect(textarea.value).toBe('wrong artist');
    expect(screen.getByRole('button', { name: /update flag/i })).toBeInTheDocument();
  });

  test('submits with reason and notes; calls invalidateQueries on success', async () => {
    const onClose = vi.fn();
    render(FlagPopover, { props: { track, onClose } });
    const select = screen.getByRole('combobox');
    await fireEvent.change(select, { target: { value: 'duplicate' } });
    const textarea = screen.getByPlaceholderText(/what's wrong/i);
    await fireEvent.input(textarea, { target: { value: 'same recording' } });
    await fireEvent.click(screen.getByRole('button', { name: /^flag$/i }));
    await Promise.resolve();
    await Promise.resolve();
    expect(flagTrack).toHaveBeenCalledWith({
      track_id: 't1',
      reason: 'duplicate',
      notes: 'same recording'
    });
    expect(invalidateMock).toHaveBeenCalled();
    expect(onClose).toHaveBeenCalled();
  });

  test('empty notes are not sent', async () => {
    render(FlagPopover, { props: { track, onClose: vi.fn() } });
    await fireEvent.click(screen.getByRole('button', { name: /^flag$/i }));
    await Promise.resolve();
    await Promise.resolve();
    expect(flagTrack).toHaveBeenCalledWith({
      track_id: 't1',
      reason: 'bad_rip',
      notes: undefined
    });
  });

  test('cancel button calls onClose without firing flagTrack', async () => {
    const onClose = vi.fn();
    render(FlagPopover, { props: { track, onClose } });
    await fireEvent.click(screen.getByRole('button', { name: /cancel/i }));
    expect(flagTrack).not.toHaveBeenCalled();
    expect(onClose).toHaveBeenCalled();
  });
});
