// @vitest-environment jsdom
/**
 * test/grid-presets.test.ts — saved split-grid layout presets + dropdown.
 *
 * Covers persistence (round-trip, garbage tolerance, malformed drop) and the
 * dropdown behavior: empty state, save current, apply (calls back), delete.
 */

import { describe, it, expect, vi, beforeEach } from 'vitest'
import { loadPresets, savePresets, mountGridPresets, type GridPreset } from '../public/grid-presets.js'

const KEY = 'web-terminal:grid-presets'
const CURRENT: { layout: GridPreset['layout']; split: GridPreset['split'] } = {
  layout: 'grid-4',
  split: { cols: [1.5, 0.5], rows: [1, 1] },
}

beforeEach(() => localStorage.clear())

describe('grid-presets: persistence', () => {
  it('round-trips presets through localStorage', () => {
    const list: GridPreset[] = [{ name: 'wide-left', layout: 'grid-4', split: CURRENT.split }]
    savePresets(list)
    expect(loadPresets()).toEqual(list)
  })

  it('returns [] for missing or garbage storage', () => {
    expect(loadPresets()).toEqual([])
    localStorage.setItem(KEY, 'not json')
    expect(loadPresets()).toEqual([])
  })

  it('drops malformed entries', () => {
    localStorage.setItem(
      KEY,
      JSON.stringify([
        { name: 'ok', layout: 'grid-4', split: { cols: [1, 1], rows: [1, 1] } },
        { name: 'bad-layout', layout: 'nope', split: {} },
        { nope: true },
      ]),
    )
    const out = loadPresets()
    expect(out).toHaveLength(1)
    expect(out[0]!.name).toBe('ok')
  })
})

describe('grid-presets: dropdown', () => {
  let toolbar: HTMLElement
  let apply: ReturnType<typeof vi.fn>
  const mount = () => {
    apply = vi.fn()
    return mountGridPresets(toolbar, { current: () => CURRENT, apply })
  }
  beforeEach(() => {
    toolbar = document.createElement('div')
    document.body.replaceChildren(toolbar)
  })

  const openMenu = (): HTMLElement => {
    toolbar.querySelector<HTMLButtonElement>('.grid-presets-btn')!.click()
    return toolbar.querySelector<HTMLElement>('.grid-presets-menu')!
  }

  it('shows an empty state when there are no presets', () => {
    mount()
    const menu = openMenu()
    expect(menu.hidden).toBe(false)
    expect(menu.querySelector('.gp-empty')).not.toBeNull()
  })

  it('saves the current arrangement under a typed name', () => {
    mount()
    openMenu()
    const input = toolbar.querySelector<HTMLInputElement>('.gp-name')!
    input.value = 'wide-left'
    toolbar.querySelector<HTMLButtonElement>('.gp-save-btn')!.click()
    expect(loadPresets()).toEqual([{ name: 'wide-left', layout: 'grid-4', split: CURRENT.split }])
    expect(toolbar.querySelector('.gp-apply-name')?.textContent).toBe('wide-left')
  })

  it('does not save a blank name', () => {
    mount()
    openMenu()
    toolbar.querySelector<HTMLButtonElement>('.gp-save-btn')!.click()
    expect(loadPresets()).toEqual([])
  })

  it('applies a preset (calls back) and closes the menu', () => {
    savePresets([{ name: 'p1', layout: 'grid-4', split: CURRENT.split }])
    mount()
    const menu = openMenu()
    toolbar.querySelector<HTMLButtonElement>('.gp-apply')!.click()
    expect(apply).toHaveBeenCalledWith({ name: 'p1', layout: 'grid-4', split: CURRENT.split })
    expect(menu.hidden).toBe(true)
  })

  it('deletes a preset', () => {
    savePresets([{ name: 'p1', layout: 'grid-4', split: CURRENT.split }])
    mount()
    openMenu()
    toolbar.querySelector<HTMLButtonElement>('.gp-del')!.click()
    expect(loadPresets()).toEqual([])
    expect(toolbar.querySelector('.gp-empty')).not.toBeNull()
  })

  it('closes on an outside pointerdown', () => {
    mount()
    const menu = openMenu()
    expect(menu.hidden).toBe(false)
    document.dispatchEvent(new MouseEvent('pointerdown', { bubbles: true }))
    expect(menu.hidden).toBe(true)
  })

  it('closes on Escape', () => {
    mount()
    const menu = openMenu()
    document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' }))
    expect(menu.hidden).toBe(true)
  })

  it('replaces a same-named preset instead of duplicating', () => {
    savePresets([{ name: 'dup', layout: 'split-2', split: { cols: [1, 1], rows: [1] } }])
    mount()
    openMenu()
    const input = toolbar.querySelector<HTMLInputElement>('.gp-name')!
    input.value = 'dup'
    toolbar.querySelector<HTMLButtonElement>('.gp-save-btn')!.click()
    const out = loadPresets()
    expect(out).toHaveLength(1)
    expect(out[0]!.layout).toBe('grid-4') // overwritten with the current arrangement
  })
})
