import { fireEvent, render, screen } from '@testing-library/react';
import * as React from 'react';
import { expect, describe, it, vi } from 'vitest';
import { PositionReference } from '../../Enums/PositionReference';
import { IContainerProperties } from '../../Interfaces/IContainerProperties';
import { Orientation } from '../../Enums/Orientation';
import { ContainerProperties } from './ContainerProperties';
import { DEFAULT_DIMENSION_OPTION } from '../../utils/default';

describe.concurrent('Properties', () => {
  it('No properties', () => {
    render(<ContainerProperties
      properties={undefined}
      onChange={() => {}}
      symbols={new Map()}
    />);

    expect(screen.queryByText('id')).toBeNull();
    expect(screen.queryByText('parentId')).toBeNull();
    expect(screen.queryByText('x')).toBeNull();
    expect(screen.queryByText('y')).toBeNull();
  });

  it('Some properties, change values with dynamic input', () => {
    const prop: IContainerProperties = {
      id: 'stuff',
      type: 'type',
      parentId: 'parentId',
      linkedSymbolId: '',
      displayedText: 'stuff',
      orientation: Orientation.Horizontal,
      x: 1,
      y: 1,
      width: 1,
      height: 1,
      minWidth: 1,
      maxWidth: Infinity,
      minHeight: 1,
      maxHeight: Infinity,
      margin: {},
      positionReference: PositionReference.TopLeft,
      isFlex: false,
      isAnchor: false,
      warning: '',
      hideChildrenInTreeview: false,
      dimensionOptions: {
        childrenDimensions: DEFAULT_DIMENSION_OPTION,
        selfDimensions: DEFAULT_DIMENSION_OPTION,
        selfMarginsDimensions: DEFAULT_DIMENSION_OPTION,
        markPosition: [],
        dimensionWithMarks: DEFAULT_DIMENSION_OPTION
      }
    };

    const handleChange = vi.fn((key, value) => {
      (prop as any)[key] = value;
    });

    const { container, rerender } = render(<ContainerProperties
      properties={prop}
      onChange={handleChange}
      symbols={new Map()}
    />);

    expect(screen.queryByText('id')).toBeDefined();
    expect(screen.queryByText('parentId')).toBeDefined();
    expect(screen.queryByText('x')).toBeDefined();
    expect(screen.queryByText('y')).toBeDefined();

    let propertyId = container.querySelector('#id');
    let propertyParentId = container.querySelector('#parentId');
    let propertyX = container.querySelector('#x');
    let propertyY = container.querySelector('#y');
    expect(propertyId).toBeDefined();
    expect((propertyId as HTMLInputElement).value).toBe('stuff');
    expect(propertyParentId).toBeDefined();
    expect((propertyParentId as HTMLInputElement).value).toBe('parentId');
    expect(propertyX).toBeDefined();
    expect((propertyX as HTMLInputElement).value).toBe('1');
    expect(propertyY).toBeDefined();
    expect((propertyY as HTMLInputElement).value).toBe('1');

    fireEvent.change(propertyId as Element, { target: { value: 'stuffed' } });
    fireEvent.change(propertyParentId as Element, { target: { value: 'parentedId' } });
    fireEvent.change(propertyX as Element, { target: { value: '2' } });
    fireEvent.change(propertyY as Element, { target: { value: '2' } });

    expect(handleChange).toBeCalledTimes(0);
    expect(prop.x).toBe(1);
    expect(prop.y).toBe(1);

    fireEvent.keyUp(propertyX as Element, { key: 'Enter' });
    fireEvent.keyUp(propertyY as Element, { key: 'Enter' });
    expect(handleChange).toBeCalledTimes(2);

    expect(prop.id).toBe('stuff');
    expect(prop.parentId).toBe('parentId');
    expect(prop.x).toBe(2);
    expect(prop.y).toBe(2);
    rerender(<ContainerProperties
      properties={Object.assign({}, prop)}
      onChange={handleChange}
      symbols={new Map()}
    />);

    propertyId = container.querySelector('#id');
    propertyParentId = container.querySelector('#parentId');
    propertyX = container.querySelector('#x');
    propertyY = container.querySelector('#y');
    expect(propertyId).toBeDefined();
    expect((propertyId as HTMLInputElement).value).toBe('stuff');
    expect(propertyParentId).toBeDefined();
    expect((propertyParentId as HTMLInputElement).value).toBe('parentId');
    expect(propertyX).toBeDefined();
    expect((propertyX as HTMLInputElement).value).toBe('2');
    expect(propertyY).toBeDefined();
    expect((propertyY as HTMLInputElement).value).toBe('2');
  });
});
