import React from 'react';
import { fireEvent, render, waitFor } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { KGCore } from '../../core/KGCore';
import type { ChordGuideData } from '../../core/ChordGuideTypes';
import { KGPianoRollState } from '../../core/state/KGPianoRollState';
import { getMatchingChordGuideCandidatesForPitch } from '../../util/chordGuideDataUtil';
import chordGuideDataJson from '../../../public/resources/modes/chord_guide.json';

const chordGuideData = chordGuideDataJson as ChordGuideData;

vi.mock('../common', () => ({
  Playhead: () => null,
}));

import PianoGrid from './PianoGrid';

describe('PianoGrid chord-guide hover candidate state', () => {
  beforeEach(() => {
    document.documentElement.style.setProperty('--region-grid-beat-width', '40');
    document.documentElement.style.setProperty('--region-piano-key-height', '20');
    KGCore.CHORD_GUIDE_DATA = structuredClone(chordGuideData);
    KGCore.FUNCTIONAL_CHORDS_DATA = {
      ionian: { steps: [2, 2, 1, 2, 2, 2, 1] },
      aeolian: { steps: [2, 1, 2, 2, 1, 2, 2] },
    } as unknown as typeof KGCore.FUNCTIONAL_CHORDS_DATA;
    KGPianoRollState.instance().setCurrentHoveredChordGuideCandidate(null);
    KGPianoRollState.instance().setCurrentMatchingChords([]);
    KGPianoRollState.instance().setCurrentSelectedChordIndex(0);
    KGPianoRollState.instance().setCurrentChordCursorPitch(null);
  });

  it('tracks the hovered candidate, updates on candidate cycling, and clears on mouse leave', async () => {
    const gridRef = { current: null as HTMLDivElement | null };
    const { container } = render(
      <PianoGrid
        gridRef={gridRef}
        onDoubleClick={() => {}}
        onClick={() => {}}
        onMouseDown={() => {}}
        isBoxSelecting={false}
        selectionBox={{ startX: 0, startY: 0, endX: 0, endY: 0 }}
        selectedMode="ionian"
        keySignature="C major"
        chordGuide="T"
        chordGuideKeySignature="C major"
        chordGuideMode="ionian"
      >
        {null}
      </PianoGrid>
    );

    const pianoGrid = container.querySelector('.piano-grid') as HTMLDivElement;
    pianoGrid.getBoundingClientRect = () => ({
      left: 0,
      top: 0,
      width: 800,
      height: 1200,
      right: 800,
      bottom: 1200,
      x: 0,
      y: 0,
      toJSON: () => ({}),
    });

    fireEvent.mouseMove(pianoGrid, { clientX: 10, clientY: 941 });

    const expectedCandidates = getMatchingChordGuideCandidatesForPitch(60, 'C major', 'ionian', 'T');
    expect(expectedCandidates.length).toBeGreaterThan(1);

    await waitFor(() => {
      expect(KGPianoRollState.instance().getCurrentHoveredChordGuideCandidate()).toMatchObject({
        name: expectedCandidates[0].item.name,
        resolvedNotes: expectedCandidates[0].item.resolvedNotes,
        note: expectedCandidates[0].item.note,
      });
    });

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    (window as any).__pianoGridSwitchChord(1);

    await waitFor(() => {
      expect(KGPianoRollState.instance().getCurrentHoveredChordGuideCandidate()).toMatchObject({
        name: expectedCandidates[1].item.name,
        resolvedNotes: expectedCandidates[1].item.resolvedNotes,
        note: expectedCandidates[1].item.note,
      });
    });

    fireEvent.mouseLeave(pianoGrid);

    await waitFor(() => {
      expect(KGPianoRollState.instance().getCurrentHoveredChordGuideCandidate()).toBeNull();
    });
  });
});
