/**
 * @jest-environment jsdom
 */

import { render } from '@testing-library/react'
import { RJT_CONFIG, Serializable } from '../../core'
import { RJTProvider } from '../context'
import { Inflater, mapSDUI } from '../Inflater'

const config: RJT_CONFIG = {
  components: {
    Simple: Serializable('Simple', (props) => <button {...props}>Simple</button>),
    Complex: Serializable('Complex', (props) => <div {...props} />)
  },
  actions: {
    handlePress: jest.fn()
  },
  constants: {
    windowWidth: 100,
    windowHeight: 200
  }
}

describe('Inflater', () => {
  afterEach(() => {
    jest.resetAllMocks()
  })

  it('inflates simple Component', () => {
    const { asFragment } = render(
      <RJTProvider config={config}>
        <Inflater
          sdui={{
            type: '__RJT_COMPONENT__',
            name: 'Simple',
            props: {
              testID: 'test'
            }
          }}
        />
      </RJTProvider>
    )
    expect(asFragment()).toMatchSnapshot()
  })

  it('inflates complex Component', () => {
    const { asFragment } = render(
      <RJTProvider config={config}>
        <Inflater
          sdui={{
            type: '__RJT_COMPONENT__',
            name: 'Complex',
            props: {
              testID: 'test',
              children: [
                {
                  type: '__RJT_COMPONENT__',
                  name: 'Simple',
                  props: {}
                },
                {
                  type: '__RJT_COMPONENT__',
                  name: 'Simple',
                  props: {}
                }
              ]
            }
          }}
        />
      </RJTProvider>
    )
    expect(asFragment()).toMatchSnapshot()
  })

  it('inflates fragment', () => {
    const { asFragment } = render(
      <RJTProvider config={config}>
        <Inflater
          sdui={
            {
              type: '__RJT_COMPONENT__',
              name: 'Complex',
              props: {
                children: [
                  {
                    type: '__RJT_COMPONENT__',
                    name: 'Simple',
                    props: {}
                  },
                  {
                    type: '__RJT_FRAGMENT__',
                    children: [
                      {
                        type: '__RJT_COMPONENT__',
                        name: 'Simple',
                        props: {}
                      },
                      {
                        type: '__RJT_COMPONENT__',
                        name: 'Simple',
                        props: {}
                      }
                    ]
                  }
                ]
              }
            }
          }
        />
      </RJTProvider>
    )
    expect(asFragment()).toMatchSnapshot()
  })

  it('inflates props Action', () => {
    const element = mapSDUI(
      {
        type: '__RJT_COMPONENT__',
        name: 'Simple',
        props: {
          onclick: {
            type: '__RJT_ACTION__',
            name: 'handlePress',
            params: ['arg1']
          }
        }
      },
      config
    )
    element.props.onclick()
    expect(config.actions.handlePress).toBeCalledWith('arg1')
    const { asFragment } = render(element)
    expect(asFragment()).toMatchSnapshot()
  })

  it('inflates child Action', () => {
    const element = mapSDUI(
      {
        type: '__RJT_COMPONENT__',
        name: 'Complex',
        props: {
          children: {
            type: '__RJT_ACTION__',
            name: 'handlePress',
            params: ['args1', 'args2']
          }
        }
      },
      config
    )
    element.props.children()
    expect(config.actions.handlePress).toBeCalledWith('args1', 'args2')
    const { asFragment } = render(element)
    expect(asFragment()).toMatchSnapshot()
  })

  it('inflates constants', () => {
    const element = mapSDUI(
      {
        type: '__RJT_COMPONENT__',
        name: 'Complex',
        props: {
          height: {
            type: '__RJT_CONSTANT__',
            name: 'windowHeight'
          },
          children: {
            type: '__RJT_CONSTANT__',
            name: 'windowWidth'
          }
        }
      },
      config
    )
    const { asFragment } = render(element)
    expect(asFragment()).toMatchSnapshot()
  })

  it('inflates client calculation', () => {
    const element = mapSDUI(
      {
        type: '__RJT_COMPONENT__',
        name: 'Simple',
        props: {
          height: {
            type: '__RJT_OPERATION__',
            operation: '+',
            operands: [
              {
                type: '__RJT_CONSTANT__',
                name: 'windowHeight'
              },
              20
            ]
          }
        }
      },
      config
    )
    const { asFragment } = render(element)

    expect(element.props.height).toBe(config.constants.windowHeight as number + 20)
    expect(asFragment()).toMatchSnapshot()
  })
})
