import test, { expect } from '@playwright/test'
import { Editor } from 'tldraw'

declare const EDITOR_A: Editor
declare const EDITOR_B: Editor
declare const EDITOR_C: Editor

// We're just testing the events, not the actual results.

test.describe('Focus', () => {
	test('focus events', async ({ page }) => {
		await page.goto('http://localhost:5420/multiple/full')
		await page.waitForSelector('.tl-canvas')

		const EditorA = (await page.$(`.A`))!
		const EditorB = (await page.$(`.B`))!
		const EditorC = (await page.$(`.C`))!
		expect(EditorA).toBeTruthy()
		expect(EditorB).toBeTruthy()
		expect(EditorC).toBeTruthy()

		async function isOnlyFocused(id: 'A' | 'B' | 'C' | null) {
			let activeElement: string | null = null
			const isA = await EditorA.evaluate(
				(node) => document.activeElement === node || node.contains(document.activeElement)
			)
			const isB = await EditorB.evaluate(
				(node) => document.activeElement === node || node.contains(document.activeElement)
			)

			const isC = await EditorC.evaluate(
				(node) => document.activeElement === node || node.contains(document.activeElement)
			)

			activeElement = isA ? 'A' : isB ? 'B' : isC ? 'C' : null

			expect(
				activeElement,
				`Active element should have been ${id}, but was ${activeElement ?? 'null'} instead`
			).toBe(id)

			await page.evaluate(
				({ id }) => {
					if (
						!(
							EDITOR_A.getInstanceState().isFocused === (id === 'A') &&
							EDITOR_B.getInstanceState().isFocused === (id === 'B') &&
							EDITOR_C.getInstanceState().isFocused === (id === 'C')
						)
					) {
						throw Error('isFocused is not correct')
					}
				},
				{ id }
			)
		}

		// Component A has autofocus
		// Component B does not
		// Component C does not
		// Component B and C share persistence id

		await (await page.$('body'))?.click()

		await isOnlyFocused('A')

		await EditorA.click()

		await isOnlyFocused('A')

		await EditorA.click()

		await isOnlyFocused('A')

		await EditorB.click()

		await isOnlyFocused('B')

		// Escape does not break focus
		await page.keyboard.press('Escape')

		await isOnlyFocused('B')
	})

	test('kbds when not focused', async ({ page }) => {
		await page.goto('http://localhost:5420/multiple/full')
		await page.waitForSelector('.tl-canvas')

		// Should not have any shapes on the page
		expect(await page.evaluate(() => EDITOR_A.getCurrentPageShapes().length)).toBe(0)

		const EditorA = (await page.$(`.A`))!
		await page.keyboard.press('r')
		await EditorA.click({ position: { x: 100, y: 100 } })

		// Should not have created a shape
		expect(await page.evaluate(() => EDITOR_A.getCurrentPageShapes().length)).toBe(1)

		const TextArea = page.getByTestId(`textarea`)
		await TextArea.focus()
		await page.keyboard.type('hello world')
		await page.keyboard.press('Control+A')
		await page.keyboard.press('Delete')

		// Should not have deleted the page
		expect(await page.evaluate(() => EDITOR_A.getCurrentPageShapes().length)).toBe(1)
	})

	test('kbds when focused', async ({ page }) => {
		await page.goto('http://localhost:5420/multiple/full')
		await page.waitForSelector('.tl-canvas')

		const EditorA = (await page.$(`.A`))!
		const EditorB = (await page.$(`.B`))!
		const EditorC = (await page.$(`.C`))!
		expect(EditorA).toBeTruthy()
		expect(EditorB).toBeTruthy()
		expect(EditorC).toBeTruthy()

		await (await page.$('body'))?.click()

		expect(await EditorA.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')).toBe(
			null
		)
		expect(await EditorB.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')).toBe(
			null
		)

		await page.keyboard.press('d')

		expect(
			await EditorA.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')
		).not.toBe(null)
		expect(await EditorB.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')).toBe(
			null
		)

		await EditorB.click()
		await page.waitForTimeout(100) // takes 30ms or so to focus
		await page.keyboard.press('d')

		expect(
			await EditorA.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')
		).not.toBe(null)
		expect(
			await EditorB.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')
		).not.toBe(null)
	})

	test('kbds after clicking on ui elements', async ({ page }) => {
		await page.goto('http://localhost:5420/end-to-end')
		await page.waitForSelector('.tl-canvas')

		const EditorA = (await page.$(`.tl-container`))!
		expect(EditorA).toBeTruthy()

		const drawButton = await EditorA.$('.tlui-button[data-testid="tools.draw"]')

		// select button should be selected, not the draw button
		expect(await EditorA.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')).toBe(
			null
		)

		await drawButton?.click()

		// draw button should be selected now
		expect(
			await EditorA.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')
		).not.toBe(null)

		await page.keyboard.press('v')

		// select button should be selected again
		expect(await EditorA.$('.tlui-button[data-testid="tools.draw"][data-state="selected"]')).toBe(
			null
		)
	})
})
