import { useState } from 'react'
import { describe, expect, it } from 'vitest'
import { fireEvent, render, screen } from '@testing-library/react'
import type { AnyFieldDefinition, FieldGroup } from '@platform-modules/fields'
import { COMPLETE_FIELD_TYPES, FieldDefinitionListBuilder, FieldGroupDefinitionBuilder } from './definition-builder.js'

const text: AnyFieldDefinition = { key:'title', name:'title', label:'Title', type:'text', settings:{} }
const baseGroup: FieldGroup = {
  key:'content_fields', title:'Content fields', fields:[text],
  location:[[{parameter:'entityType',operator:'eq',value:'content'}]], active:true,
}

function GroupHost({ initial=baseGroup }:{initial?:FieldGroup}) {
  const [value,setValue]=useState(initial)
  return <><FieldGroupDefinitionBuilder value={value} onChange={setValue}/><output data-testid="group-value">{JSON.stringify(value)}</output></>
}
function FieldsHost({ initial }:{initial:readonly AnyFieldDefinition[]}) {
  const [value,setValue]=useState(initial)
  return <><FieldDefinitionListBuilder value={value} onChange={setValue}/><output data-testid="fields-value">{JSON.stringify(value)}</output></>
}

describe('modern field definition builders',()=>{
  it('offers every modern built-in type',()=>{
    render(<FieldsHost initial={[text]}/>)
    const select=screen.getByLabelText('Field 1 type') as HTMLSelectElement
    expect(Array.from(select.options,o=>o.value)).toEqual([...COMPLETE_FIELD_TYPES])
    expect(COMPLETE_FIELD_TYPES).toContain('repeater')
    expect(COMPLETE_FIELD_TYPES).toContain('flexible')
    expect(COMPLETE_FIELD_TYPES).toContain('clone')
    expect(COMPLETE_FIELD_TYPES).toContain('map')
  })

  it('authors recursive group children and flexible layouts',()=>{
    const recursive:readonly AnyFieldDefinition[]=[
      {key:'grouped',name:'grouped',label:'Grouped',type:'group',settings:{fields:[text]}},
      {key:'flex',name:'flex',label:'Flexible',type:'flexible',settings:{layouts:[{key:'hero',name:'hero',label:'Hero',fields:[text]}]}},
    ]
    render(<FieldsHost initial={recursive}/>)
    const addButtons=screen.getAllByRole('button',{name:'Add field'})
    fireEvent.click(addButtons[0]!)
    expect(screen.getByLabelText('Grouped child fields')).toBeTruthy()
    fireEvent.click(screen.getByRole('button',{name:'Add layout'}))
    expect(screen.getByLabelText('Layout 2 key')).toBeTruthy()
    const stored=JSON.parse(screen.getByTestId('fields-value').textContent??'[]') as Array<{settings:{fields?:unknown[];layouts?:unknown[]}}>
    expect(stored[0]!.settings.fields).toHaveLength(2)
    expect(stored[1]!.settings.layouts).toHaveLength(2)
  })

  it('edits AND/OR conditional rules without flattening groups',()=>{
    const conditional:AnyFieldDefinition={...text,conditionalLogic:[[{fieldPath:['enabled'],operator:'eq',value:true}]]}
    render(<FieldsHost initial={[conditional]}/>)
    fireEvent.click(screen.getByRole('button',{name:'Add AND condition'}))
    fireEvent.click(screen.getByRole('button',{name:'Add OR group'}))
    expect(screen.getByLabelText('Condition 1.2 field path')).toBeTruthy()
    expect(screen.getByLabelText('Condition 2.1 field path')).toBeTruthy()
    const stored=JSON.parse(screen.getByTestId('fields-value').textContent??'[]') as Array<{conditionalLogic:unknown[][]}>
    expect(stored[0]!.conditionalLogic.map(group=>group.length)).toEqual([2,1])
  })

  it('edits AND/OR location rules while preserving nested grouping',()=>{
    render(<GroupHost/>)
    fireEvent.click(screen.getByRole('button',{name:'Add AND location rule'}))
    fireEvent.click(screen.getByRole('button',{name:'Add OR location group'}))
    fireEvent.change(screen.getByLabelText('Location 2.1 parameter'),{target:{value:'status'}})
    const stored=JSON.parse(screen.getByTestId('group-value').textContent??'{}') as {location:Array<Array<{parameter:string}>>}
    expect(stored.location.map(group=>group.length)).toEqual([2,1])
    expect(stored.location[1]![0]!.parameter).toBe('status')
  })

  it('surfaces core parser validation failures as focusable alerts',()=>{
    render(<GroupHost initial={{...baseGroup,key:'2bad'}}/>)
    const alert=screen.getByRole('alert')
    expect(alert.textContent?.toLowerCase()).toContain('key')
    expect(alert.getAttribute('tabindex')).toBe('0')
  })


  it('preserves focus while editing keys and moving definitions',()=>{
    render(<FieldsHost initial={[text,{...text,key:'summary',name:'summary',label:'Summary'}]}/>)
    const keyInput=screen.getByLabelText('Field 1 key') as HTMLInputElement
    keyInput.focus()
    fireEvent.change(keyInput,{target:{value:'headline'}})
    expect(document.activeElement).toBe(keyInput)
    const move=screen.getByRole('button',{name:'Move Summary up'})
    move.focus();fireEvent.click(move)
    expect(document.activeElement).toBe(move)
  })

  it('reorders definitions with keyboard-focus-safe boundary controls',()=>{
    render(<FieldsHost initial={[text,{...text,key:'summary',name:'summary',label:'Summary'}]}/>)
    const boundary=screen.getByRole('button',{name:'Move Title up'})
    boundary.focus();fireEvent.click(boundary)
    expect(boundary.getAttribute('aria-disabled')).toBe('true')
    expect(document.activeElement).toBe(boundary)
    fireEvent.click(screen.getByRole('button',{name:'Move Summary up'}))
    const stored=JSON.parse(screen.getByTestId('fields-value').textContent??'[]') as Array<{key:string}>
    expect(stored.map(field=>field.key)).toEqual(['summary','title'])
  })
})
