import * as React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { ReviewScorecard, ReviewNotes, DEFAULT_REVIEW_DIMENSIONS } from '../index';
import type { ReviewScore, ReviewNote } from '../index';

describe('ReviewScorecard', () => {
  it('exposes the default guardrail dimensions', () => {
    expect(DEFAULT_REVIEW_DIMENSIONS.map((d) => d.key)).toEqual([
      'political-sensitivity',
      'source-reliability',
      'recency',
      'tone-and-voice',
      'accuracy',
    ]);
  });

  it('emits the next value when a verdict is chosen', () => {
    const onChange = jest.fn();
    render(<ReviewScorecard value={{}} onChange={onChange} />);
    fireEvent.click(screen.getByRole('button', { name: 'Revise' }));
    expect(onChange).toHaveBeenCalledWith({ verdict: 'revise' });
  });

  it('emits the next value (immutably) when a dimension score is clicked', () => {
    const onChange = jest.fn();
    const value: ReviewScore = { verdict: 'approve' };
    render(<ReviewScorecard value={value} onChange={onChange} />);
    fireEvent.click(screen.getByLabelText('Accuracy score 4'));
    expect(onChange).toHaveBeenCalledWith({ verdict: 'approve', dimensions: { accuracy: { score: 4 } } });
    // original value not mutated
    expect(value).toEqual({ verdict: 'approve' });
  });

  it('merges a dimension note without dropping an existing score', () => {
    const onChange = jest.fn();
    render(
      <ReviewScorecard value={{ dimensions: { accuracy: { score: 5 } } }} onChange={onChange} />,
    );
    fireEvent.change(screen.getByLabelText('Accuracy note'), { target: { value: 'Well cited' } });
    expect(onChange).toHaveBeenCalledWith({ dimensions: { accuracy: { score: 5, note: 'Well cited' } } });
  });

  it('emits the overall note', () => {
    const onChange = jest.fn();
    render(<ReviewScorecard value={{}} onChange={onChange} />);
    fireEvent.change(screen.getByLabelText('Overall note'), { target: { value: 'Looks solid.' } });
    expect(onChange).toHaveBeenCalledWith({ overallNote: 'Looks solid.' });
  });

  it('renders read-only values with no inputs', () => {
    render(
      <ReviewScorecard
        readOnly
        onChange={jest.fn()}
        dimensions={[{ key: 'accuracy', label: 'Accuracy' }]}
        value={{ verdict: 'approve', dimensions: { accuracy: { score: 5, note: 'Solid sourcing' } }, overallNote: 'Ship it' }}
      />,
    );
    expect(screen.getByText('Approve')).toBeInTheDocument();
    expect(screen.getByText('Solid sourcing')).toBeInTheDocument();
    expect(screen.getByText('Ship it')).toBeInTheDocument();
    // no interactive inputs in read-only mode
    expect(screen.queryByRole('textbox')).not.toBeInTheDocument();
    expect(screen.queryByLabelText('Accuracy score 5')).not.toBeInTheDocument();
    expect(screen.queryByRole('button', { name: 'Revise' })).not.toBeInTheDocument();
  });
});

describe('ReviewNotes', () => {
  const notes: ReviewNote[] = [
    { id: 'n1', body: 'Tighten the intro.', author: 'Alex', at: new Date().toISOString() },
    { id: 'n2', body: 'Fixed the citation.', author: 'Sam', resolved: true },
  ];

  it('shows the empty message when there are no notes', () => {
    render(<ReviewNotes notes={[]} emptyMessage="Nothing flagged." />);
    expect(screen.getByText('Nothing flagged.')).toBeInTheDocument();
  });

  it('renders notes with author and resolved styling', () => {
    render(<ReviewNotes notes={notes} />);
    expect(screen.getByText('Tighten the intro.')).toBeInTheDocument();
    expect(screen.getByText('Alex')).toBeInTheDocument();
    expect(screen.getByText('Resolved')).toBeInTheDocument();
    expect(screen.getByText('Today')).toBeInTheDocument();
  });

  it('adds a note via the composer', () => {
    const onAdd = jest.fn();
    render(<ReviewNotes notes={[]} onAdd={onAdd} />);
    fireEvent.change(screen.getByLabelText('Add a note'), { target: { value: '  Needs a stronger hook  ' } });
    fireEvent.click(screen.getByRole('button', { name: 'Add note' }));
    expect(onAdd).toHaveBeenCalledWith('Needs a stronger hook');
  });

  it('disables the add button until there is text', () => {
    render(<ReviewNotes notes={[]} onAdd={jest.fn()} />);
    expect(screen.getByRole('button', { name: 'Add note' })).toBeDisabled();
  });

  it('resolves an unresolved note', () => {
    const onResolve = jest.fn();
    render(<ReviewNotes notes={notes} onResolve={onResolve} />);
    // only the unresolved note (n1) exposes a Resolve action
    fireEvent.click(screen.getByRole('button', { name: 'Resolve' }));
    expect(onResolve).toHaveBeenCalledWith('n1');
  });

  it('hides the composer and resolve actions in read-only mode', () => {
    render(<ReviewNotes notes={notes} onAdd={jest.fn()} onResolve={jest.fn()} readOnly />);
    expect(screen.queryByRole('button', { name: 'Add note' })).not.toBeInTheDocument();
    expect(screen.queryByRole('button', { name: 'Resolve' })).not.toBeInTheDocument();
  });
});
