import { test, expect } from '@playwright/test'
import fs from 'fs'
import path from 'path'
import { createFixtureVaultCopy, openFixtureVaultDesktopHarness, removeFixtureVaultCopy } from '../helpers/fixtureVault'
import { openCommandPalette, sendShortcut } from './helpers'

let tempVaultDir: string

function writeFixtureNote(vaultPath: string, filename: string, content: string): string {
  const notePath = path.join(vaultPath, filename)
  fs.writeFileSync(notePath, content)
  return notePath
}

function toast(page: import('@playwright/test').Page) {
  return page.locator('.fixed.bottom-8')
}

async function createTypeFromCommandPalette(page: import('@playwright/test').Page, typeName: string): Promise<void> {
  await openCommandPalette(page)
  await page.locator('input[placeholder="Type a command..."]').fill('new type')
  await page.keyboard.press('Enter')

  const dialog = page.getByRole('dialog', { name: 'Create New Type' })
  const title = dialog.getByText('Create New Type', { exact: true })
  const typeInput = dialog.getByPlaceholder('e.g. Recipe, Book, Habit...')
  await expect(title).toBeVisible()
  await typeInput.fill(typeName)
  await dialog.getByRole('button', { name: 'Create' }).click()
  await expect(dialog).toHaveCount(0)
}

test.describe('Collision-safe create flows', () => {
  test.beforeEach(async ({ page }) => {
    tempVaultDir = createFixtureVaultCopy()
    await page.setViewportSize({ width: 1600, height: 900 })
  })

  test.afterEach(() => {
    removeFixtureVaultCopy(tempVaultDir)
  })

  test('missing-type creation keeps the dialog open when a root filename already exists', async ({ page }) => {
    const collidingPath = writeFixtureNote(
      tempVaultDir,
      'hotel.md',
      '---\ntype: Note\n---\n# Existing Hotel Note\n',
    )
    writeFixtureNote(
      tempVaultDir,
      'hotel-guide.md',
      '---\ntype: Hotel\nstatus: Active\n---\n# Hotel Guide\n',
    )

    await openFixtureVaultDesktopHarness(page, tempVaultDir)
    await page.getByText('Hotel Guide', { exact: true }).click()
    await sendShortcut(page, 'i', ['Control', 'Shift'])

    const warning = page.getByTestId('missing-type-warning')
    await expect(warning).toBeVisible()
    await warning.focus()
    await page.keyboard.press('Enter')

    const dialog = page.getByRole('dialog')
    await expect(dialog).toBeVisible()
    await expect(dialog.getByPlaceholder('e.g. Recipe, Book, Habit...')).toHaveValue('Hotel')
    await page.keyboard.press('Enter')

    await expect(dialog).toBeVisible()
    await expect(toast(page)).toContainText('Cannot create type "Hotel" because hotel.md already exists')
    expect(fs.readFileSync(collidingPath, 'utf8')).toContain('# Existing Hotel Note')
  })

  test('relationship create-and-open keeps the inline input active on filename collision', async ({ page }) => {
    const collidingPath = writeFixtureNote(
      tempVaultDir,
      'briefing.md',
      '---\ntype: Note\n---\n# Weekly Sync\n',
    )

    await openFixtureVaultDesktopHarness(page, tempVaultDir)
    await page.getByText('Team Meeting', { exact: true }).click()
    await sendShortcut(page, 'i', ['Control', 'Shift'])

    const addButton = page.getByTestId('add-relation-ref').first()
    await expect(addButton).toBeVisible()
    await addButton.click()
    const input = page.getByTestId('add-relation-ref-input')
    await expect(input).toBeVisible()
    await input.fill('Briefing!')
    await page.waitForTimeout(300)

    await page.getByTestId('create-and-open-option').click()

    await expect(input).toBeVisible()
    await expect(toast(page)).toContainText('Cannot create note "Briefing!" because briefing.md already exists')
    expect(fs.readFileSync(collidingPath, 'utf8')).toContain('# Weekly Sync')
  })

  test('command palette type creation handles the built-in Note type without an unhandled write', async ({ page }) => {
    const defaultNoteTypePath = writeFixtureNote(
      tempVaultDir,
      'note.md',
      '---\ntype: Type\n---\n# Note\n',
    )

    await openFixtureVaultDesktopHarness(page, tempVaultDir)
    await openCommandPalette(page)
    await page.locator('input[placeholder="Type a command..."]').fill('new type')
    await page.keyboard.press('Enter')

    const dialog = page.getByRole('dialog', { name: 'Create New Type' })
    const typeInput = dialog.getByPlaceholder('e.g. Recipe, Book, Habit...')
    await expect(dialog.getByText('Create New Type', { exact: true })).toBeVisible()
    await typeInput.fill('Note')
    await dialog.getByRole('button', { name: 'Create' }).click()

    await expect(dialog).toBeVisible()
    await expect(toast(page)).toContainText('Type "Note" already exists')
    expect(fs.readFileSync(defaultNoteTypePath, 'utf8')).toContain('# Note')
  })

  test('command palette type creation maps the built-in Notes label away from notes.md collisions', async ({ page }) => {
    const existingNotesPath = writeFixtureNote(
      tempVaultDir,
      'notes.md',
      '---\ntype: Note\n---\n# Meeting Notes\n',
    )
    fs.rmSync(path.join(tempVaultDir, 'type', 'note.md'), { force: true })
    const defaultNoteTypePath = path.join(tempVaultDir, 'note.md')

    await openFixtureVaultDesktopHarness(page, tempVaultDir)
    await createTypeFromCommandPalette(page, 'Notes')

    await expect.poll(() => fs.existsSync(defaultNoteTypePath)).toBe(true)
    await expect(toast(page)).toContainText('Type "Notes" created')
    expect(fs.readFileSync(defaultNoteTypePath, 'utf8')).toContain('# Note')
    expect(fs.readFileSync(existingNotesPath, 'utf8')).toContain('# Meeting Notes')
  })

  test('unicode type creation ignores an unrelated untitled draft filename', async ({ page }) => {
    const untitledPath = writeFixtureNote(
      tempVaultDir,
      'untitled.md',
      '---\ntype: Note\n---\n# Existing Untitled Note\n',
    )
    const createdTypePath = path.join(tempVaultDir, '停智慧.md')

    await openFixtureVaultDesktopHarness(page, tempVaultDir)
    await createTypeFromCommandPalette(page, '停智慧')

    await expect.poll(() => fs.existsSync(createdTypePath)).toBe(true)
    expect(fs.readFileSync(createdTypePath, 'utf8')).toContain('type: Type')
    expect(fs.readFileSync(untitledPath, 'utf8')).toContain('# Existing Untitled Note')
  })
})
