import * as React from 'react';
import { PropertyType } from '../../Enums/PropertyType';
import { type IContainerProperties } from '../../Interfaces/IContainerProperties';
import { type ISymbolModel } from '../../Interfaces/ISymbolModel';
import {
  SHOW_BORROWER_DIMENSIONS,
  SHOW_CHILDREN_DIMENSIONS,
  SHOW_SELF_DIMENSIONS,
  SHOW_SELF_MARGINS_DIMENSIONS
} from '../../utils/default';
import {
  ApplyWidthMargin,
  ApplyXMargin,
  RemoveWidthMargin,
  RemoveXMargin,
  RestoreX,
  RestoreY,
  TransformX,
  TransformY
} from '../../utils/svg';
import { Text } from '../Text/Text';
import { InputGroup } from '../InputGroup/InputGroup';
import { TextInputGroup } from '../InputGroup/TextInputGroup';
import { Select } from '../Select/Select';
import { ToggleButton, ToggleType } from '../ToggleButton/ToggleButton';
import { PositionReferenceSelector } from '../RadioGroupButtons/PositionReferenceSelector';
import { OrientationSelector } from '../RadioGroupButtons/OrientationSelector';
import { OrientationCheckboxes } from '../CheckboxGroupButtons/OrientationCheckboxes';
import { PositionCheckboxes } from '../CheckboxGroupButtons/PositionCheckboxes';
import { Category } from '../Category/Category';
import { Orientation } from '../../Enums/Orientation';
import { FindContainerById } from '../../utils/itertools';
import { type IContainerModel } from '../../Interfaces/IContainerModel';

interface IContainerFormProps {
  containers: Map<string, IContainerModel>
  properties: IContainerProperties
  symbols: Map<string, ISymbolModel>
  onChange: (key: string, value: string | number | boolean | number[], type?: PropertyType) => void
}

export function ContainerForm(props: IContainerFormProps): JSX.Element {
  const categoryHeight = 'h-11';
  const parent = FindContainerById(props.containers, props.properties.parentId);
  const isVertical = parent?.properties.orientation === Orientation.Vertical;
  return (
    <div className='grid grid-cols-1 gap-y-4 items-center'>
      <TextInputGroup
        id={`${props.properties.id}-displayedText`}
        labelText={Text({ textId: '@ContainerDisplayedText' })}
        inputKey='displayedText'
        labelClassName=''
        inputClassName=''
        type='string'
        value={props.properties.displayedText?.toString()}
        onChange={(value) => { props.onChange('displayedText', value); }}/>
      <OrientationSelector
        id='orientation'
        name='Orientation'
        labelText={Text({ textId: '@ContainerOrientation' })}
        value={props.properties.orientation}
        onChange={props.onChange}
      />

      <Category
        category={{
          Type: 'Properties',
          DisplayedText: Text({ textId: '@ContainerProperties' })
        }}
        heightClass={`${categoryHeight}`}
      >
        <div className='grid grid-cols-1 gap-y-6 items-center prop-category-body'>
          <div>
            <InputGroup
              labelText={Text({ textId: '@ContainerName' })}
              inputKey='id'
              labelClassName=''
              inputClassName=''
              type='string'
              value={props.properties.id.toString()}
              isDisabled={true}/>
          </div>
          <div>
            <InputGroup
              labelText={Text({ textId: '@ContainerParentName' })}
              inputKey='parentId'
              labelClassName=''
              inputClassName=''
              type='string'
              value={props.properties.parentId}
              isDisabled={true}/>
          </div>
          <div>
            <InputGroup
              labelText={Text({ textId: '@ContainerType' })}
              inputKey='type'
              labelClassName=''
              inputClassName=''
              type='string'
              value={props.properties.type}
              isDisabled={true}/>
          </div>
        </div>
      </Category>

      <Category category={{
        Type: 'Position',
        DisplayedText: Text({ textId: '@ContainerPosition' })
      }}
      defaultIsOpen={true}
      heightClass={`${categoryHeight}`}
      >
        <div className='grid grid-cols-3 gap-y-2 items-center prop-category-body'>
          <TextInputGroup
            id={`${props.properties.id}-x`}
            labelText={Text({ textId: '@ContainerX' })}
            inputKey='x'
            labelClassName=''
            inputClassName='col-span-2'
            type='number'
            isDisabled={props.properties.linkedSymbolId !== ''}
            value={TransformX(
              RemoveXMargin(props.properties.x, props.properties.margin.left),
              props.properties.width,
              props.properties.positionReference
            ).toString()}
            onChange={(value) => {
              props.onChange(
                'x',
                ApplyXMargin(
                  RestoreX(
                    Number(value),
                    props.properties.width,
                    props.properties.positionReference
                  ),
                  props.properties.margin.left
                )
              );
            }}/>
          <TextInputGroup
            id={`${props.properties.id}-y`}
            labelText={Text({ textId: '@ContainerY' })}
            inputKey='y'
            labelClassName=''
            inputClassName='col-span-2'
            type='number'
            value={TransformY(
              RemoveXMargin(props.properties.y, props.properties.margin.top),
              props.properties.height,
              props.properties.positionReference
            ).toString()}
            onChange={(value) => {
              props.onChange(
                'y',
                ApplyXMargin(
                  RestoreY(
                    Number(value),
                    props.properties.height,
                    props.properties.positionReference
                  ),
                  props.properties.margin.top
                )
              );
            }}/>
        </div>
      </Category>

      <Category
        category={{
          Type: 'Size',
          DisplayedText: Text({ textId: '@ContainerSize' })
        }}
        heightClass={`${categoryHeight}`}
      >
        <div className='grid grid-cols-5 gap-y-2 items-center prop-category-body'>
          <TextInputGroup
            id={`${props.properties.id}-minWidth`}
            labelText={Text({ textId: '@ContainerMinWidth' })}
            inputKey='minWidth'
            labelClassName='col-span-2'
            inputClassName='col-span-3'
            type='number'
            min={1}
            value={props.properties.minWidth.toString()}
            onChange={(value) => { props.onChange('minWidth', Number(value)); }}/>
          <TextInputGroup
            id={`${props.properties.id}-width`}
            labelText={Text({ textId: '@ContainerWidth' })}
            inputKey='width'
            labelClassName='col-span-2'
            inputClassName='col-span-3'
            type='number'
            min={props.properties.minWidth}
            max={props.properties.maxWidth}
            value={(RemoveWidthMargin(props.properties.width,
              props.properties.margin.left,
              props.properties.margin.right)).toString()}
            onChange={(value) => {
              props.onChange('width', ApplyWidthMargin(Number(value),
                props.properties.margin.left,
                props.properties.margin.right));
            }}
            isDisabled={props.properties.isFlex}/>
          <TextInputGroup
            id={`${props.properties.id}-maxWidth`}
            labelText={Text({ textId: '@ContainerMaxWidth' })}
            inputKey='maxWidth'
            labelClassName='col-span-2'
            inputClassName='col-span-3'
            type='number'
            min={1}
            value={props.properties.maxWidth.toString()}
            onChange={(value) => { props.onChange('maxWidth', Number(value)); }}/>
          <div className='col-span-5 p-3'></div>
          <TextInputGroup
            id={`${props.properties.id}-minHeight`}
            labelText={Text({ textId: '@ContainerMinHeight' })}
            inputKey='minHeight'
            labelClassName='col-span-2'
            inputClassName='col-span-3'
            type='number'
            min={1}
            value={props.properties.minHeight.toString()}
            onChange={(value) => { props.onChange('minHeight', Number(value)); }}/>
          <TextInputGroup
            id={`${props.properties.id}-height`}
            labelText={Text({ textId: '@ContainerHeight' })}
            inputKey='height'
            labelClassName='col-span-2'
            inputClassName='col-span-3'
            type='number'
            min={props.properties.minHeight}
            max={props.properties.maxHeight}
            value={(RemoveWidthMargin(props.properties.height,
              props.properties.margin.top,
              props.properties.margin.bottom)).toString()}
            onChange={(value) => {
              props.onChange('height', ApplyWidthMargin(Number(value),
                props.properties.margin.top,
                props.properties.margin.bottom));
            }}
            isDisabled={props.properties.isFlex}
          />
          <TextInputGroup
            id={`${props.properties.id}-maxHeight`}
            labelText={Text({ textId: '@ContainerMaxHeight' })}
            inputKey='maxHeight'
            labelClassName='col-span-2'
            inputClassName='col-span-3'
            type='number'
            min={1}
            value={props.properties.maxHeight.toString()}
            onChange={(value) => { props.onChange('maxHeight', Number(value)); }}/>
        </div>
      </Category>

      <Category category={{
        Type: 'Margins',
        DisplayedText: Text({ textId: '@ContainerMargins' })
      }}
      heightClass={`${categoryHeight}`}
      >
        <div className='grid grid-cols-2 items-center gap-y-2 prop-category-body'>
          <TextInputGroup
            id={`${props.properties.id}-ml`}
            labelText={Text({ textId: '@ContainerMarginLeft' })}
            inputKey='left'
            labelClassName=''
            inputClassName=''
            type='number'
            min={0}
            value={(props.properties.margin.left ?? 0).toString()}
            onChange={(value) => { props.onChange('left', Number(value), PropertyType.Margin); }}/>
          <TextInputGroup
            id={`${props.properties.id}-mb`}
            labelText={Text({ textId: '@ContainerMarginBottom' })}
            inputKey='bottom'
            labelClassName=''
            inputClassName=''
            type='number'
            min={0}
            value={(props.properties.margin.bottom ?? 0).toString()}
            onChange={(value) => { props.onChange('bottom', Number(value), PropertyType.Margin); }}/>
          <TextInputGroup
            id={`${props.properties.id}-mt`}
            labelText={Text({ textId: '@ContainerMarginTop' })}
            inputKey='top'
            labelClassName=''
            inputClassName=''
            type='number'
            min={0}
            value={(props.properties.margin.top ?? 0).toString()}
            onChange={(value) => { props.onChange('top', Number(value), PropertyType.Margin); }}/>
          <TextInputGroup
            id={`${props.properties.id}-mr`}
            labelText={Text({ textId: '@ContainerMarginRight' })}
            inputKey='right'
            labelClassName=''
            inputClassName=''
            type='number'
            min={0}
            value={(props.properties.margin.right ?? 0).toString()}
            onChange={(value) => { props.onChange('right', Number(value), PropertyType.Margin); }}/>
        </div>
      </Category>

      <Category category={{
        Type: 'Behaviors',
        DisplayedText: Text({ textId: '@ContainerBehaviors' })
      }}
      heightClass={`${categoryHeight}`}
      >
        <div className='grid grid-cols-2 items-center gap-y-2 prop-category-body'>
          <ToggleButton
            labelText={Text({ textId: '@ContainerFlex' })}
            inputKey='isFlex'
            labelClassName=''
            inputClassName='ml-auto mr-auto block'
            type={ToggleType.Full}
            checked={props.properties.isFlex}
            onChange={(event) => { props.onChange('isFlex', event.target.checked); }}
          />
          <ToggleButton
            labelText={Text({ textId: '@ContainerAnchor' })}
            inputKey='isAnchor'
            labelClassName=''
            inputClassName='ml-auto mr-auto block'
            type={ToggleType.Full}
            checked={props.properties.isAnchor}
            onChange={(event) => { props.onChange('isAnchor', event.target.checked); }}/>
        </div>
      </Category>

      <Category category={{
        Type: 'Alignment',
        DisplayedText: Text({ textId: '@ContainerAlignment' })
      }}
      heightClass={`${categoryHeight}`}
      >
        <div className='prop-category-body'>
          <PositionReferenceSelector
            id='positionReference'
            name='PositionReference'
            labelText={Text({ textId: '@ContainerAlignmentInput' })}
            value={props.properties.positionReference}
            onChange={props.onChange}
          />
          <div className='p-3'></div>
          <Select
            inputKey='linkedSymbolId'
            labelText={Text({ textId: '@ContainerAlignWithSymbol' })}
            labelClassName=''
            inputClassName=''
            inputs={[...props.symbols.values()].filter(symbol => (symbol.isVertical === isVertical)).map(symbol => ({
              key: symbol.id,
              text: symbol.id,
              value: symbol.id
            }))}
            value={props.properties.linkedSymbolId ?? ''}
            onChange={(event) => { props.onChange('linkedSymbolId', event.target.value); }}/>
        </div>
      </Category>

      <Category category={{
        Type: 'Dimensions',
        DisplayedText: Text({ textId: '@ContainerDimensions' })
      }}
      heightClass={`${categoryHeight}`}
      >
        <div className='grid grid-cols-1 gap-6 prop-category-body'>
          {
            SHOW_SELF_DIMENSIONS &&
            <div className='grid grid-cols-1 gap-2'>
              <PositionCheckboxes
                id='positionsSelfDimensions'
                attribute='positions'
                name='ShowSelfDimensions'
                labelText={Text({ textId: '@ContainerShowDimension' })}
                value={props.properties.dimensionOptions.selfDimensions.positions}
                onChange={(key, value) => { props.onChange(key, value, PropertyType.SelfDimension); }}
              />
              <InputGroup
                labelText={Text({ textId: '@StyleStrokeColor' })}
                inputKey='color'
                labelClassName=''
                inputClassName=''
                type='color'
                value={props.properties.dimensionOptions.selfDimensions.color ?? '#000000'}
                onChange={(e) => { props.onChange('color', e.target.value, PropertyType.SelfDimension); }}/>
              <TextInputGroup
                id={`${props.properties.id}-selfDimensions-width`}
                labelText={Text({ textId: '@StyleStrokeWidth' })}
                inputKey='width'
                labelClassName=''
                inputClassName=''
                type='number'
                min={0}
                value={(props.properties.dimensionOptions.selfDimensions.width ?? 0).toString()}
                onChange={(value) => { props.onChange('width', Number(value), PropertyType.SelfDimension); }}/>
              <TextInputGroup
                id={`${props.properties.id}-selfDimensions-dasharray`}
                labelText={Text({ textId: '@StyleStrokeDashArray' })}
                inputKey='dashArray'
                labelClassName=''
                inputClassName=''
                type='text'
                value={props.properties.dimensionOptions.selfDimensions.dashArray ?? ''}
                onChange={(value) => { props.onChange('dashArray', value, PropertyType.SelfDimension); }}/>
            </div>
          }
          {
            SHOW_SELF_MARGINS_DIMENSIONS &&
            <div className='grid grid-cols-1 gap-2'>
              <PositionCheckboxes
                id='positionsSelfMarginsDimensions'
                attribute='positions'
                name='ShowSelfMarginsDimensions'
                labelText={Text({ textId: '@ContainerShowMarginsDimension' })}
                value={props.properties.dimensionOptions.selfMarginsDimensions.positions}
                onChange={(key, value) => { props.onChange(key, value, PropertyType.SelfMarginDimension); }}
              />
              <InputGroup
                labelText={Text({ textId: '@StyleStrokeColor' })}
                inputKey='color'
                labelClassName=''
                inputClassName=''
                type='color'
                value={props.properties.dimensionOptions.selfMarginsDimensions.color ?? '#000000'}
                onChange={(e) => { props.onChange('color', e.target.value, PropertyType.SelfMarginDimension); }}/>
              <TextInputGroup
                id={`${props.properties.id}-selfMarginsDimensions-width`}
                labelText={Text({ textId: '@StyleStrokeWidth' })}
                inputKey='width'
                labelClassName=''
                inputClassName=''
                type='number'
                min={0}
                value={(props.properties.dimensionOptions.selfMarginsDimensions.width ?? 0).toString()}
                onChange={(value) => { props.onChange('width', Number(value), PropertyType.SelfMarginDimension); }}/>
              <TextInputGroup
                id={`${props.properties.id}-selfMarginsDimensions-dasharray`}
                labelText={Text({ textId: '@StyleStrokeDashArray' })}
                inputKey='dashArray'
                labelClassName=''
                inputClassName=''
                type='text'
                value={props.properties.dimensionOptions.selfMarginsDimensions.dashArray ?? ''}
                onChange={(value) => { props.onChange('dashArray', value, PropertyType.SelfMarginDimension); }}/>
            </div>
          }
          {
            SHOW_CHILDREN_DIMENSIONS &&
            <div className='grid grid-cols-1 gap-2'>
              <PositionCheckboxes
                id='positionsChildrenDimensions'
                attribute='positions'
                name='ShowChildrenDimensions'
                labelText={Text({ textId: '@ContainerShowChildrenDimension' })}
                value={props.properties.dimensionOptions.childrenDimensions.positions}
                onChange={(key, value) => { props.onChange(key, value, PropertyType.ChildrenDimensions); }}
              />
              <InputGroup
                labelText={Text({ textId: '@StyleStrokeColor' })}
                inputKey='color'
                labelClassName=''
                inputClassName=''
                type='color'
                value={props.properties.dimensionOptions.childrenDimensions.color ?? '#000000'}
                onChange={(e) => { props.onChange('color', e.target.value, PropertyType.ChildrenDimensions); }}/>
              <TextInputGroup
                id={`${props.properties.id}-childrenDimensions-width`}
                labelText={Text({ textId: '@StyleStrokeWidth' })}
                inputKey='width'
                labelClassName=''
                inputClassName=''
                type='number'
                min={0}
                value={(props.properties.dimensionOptions.childrenDimensions.width ?? 0).toString()}
                onChange={(value) => { props.onChange('width', Number(value), PropertyType.ChildrenDimensions); }}/>
              <TextInputGroup
                id={`${props.properties.id}-childrenDimensions-dasharray`}
                labelText={Text({ textId: '@StyleStrokeDashArray' })}
                inputKey='dashArray'
                labelClassName=''
                inputClassName=''
                type='text'
                value={props.properties.dimensionOptions.childrenDimensions.dashArray ?? ''}
                onChange={(value) => { props.onChange('dashArray', value, PropertyType.ChildrenDimensions); }}/>
            </div>
          }
          {
            SHOW_BORROWER_DIMENSIONS &&
            <>
              <div className='grid grid-cols-1 gap-2'>
                <OrientationCheckboxes
                  id='markPosition'
                  name='MarkPosition'
                  value={props.properties.dimensionOptions.markPosition}
                  labelText={Text({ textId: '@ContainerMarkPosition' })}
                  onChange={(key, value) => { props.onChange(key, value, PropertyType.DimensionOptions); }}
                />
              </div>
              <div className='grid grid-cols-1 gap-2'>
                <PositionCheckboxes
                  id='positionsDimensionWithMarks'
                  attribute='positions'
                  name='ShowDimensionWithMarks'
                  labelText={Text({ textId: '@ContainerShowDimensionWithMarks' })}
                  value={props.properties.dimensionOptions.dimensionWithMarks.positions}
                  onChange={(key, value) => { props.onChange(key, value, PropertyType.DimensionWithMarks); }}
                />
                <InputGroup
                  labelText={Text({ textId: '@StyleStrokeColor' })}
                  inputKey='color'
                  labelClassName=''
                  inputClassName=''
                  type='color'
                  value={props.properties.dimensionOptions.dimensionWithMarks.color ?? '#000000'}
                  onChange={(e) => { props.onChange('color', e.target.value, PropertyType.DimensionWithMarks); }}/>
                <TextInputGroup
                  id={`${props.properties.id}-dimensionWithMarks-width`}
                  labelText={Text({ textId: '@StyleStrokeWidth' })}
                  inputKey='width'
                  labelClassName=''
                  inputClassName=''
                  type='number'
                  min={0}
                  value={(props.properties.dimensionOptions.dimensionWithMarks.width ?? 0).toString()}
                  onChange={(value) => { props.onChange('width', Number(value), PropertyType.DimensionWithMarks); }}/>
                <TextInputGroup
                  id={`${props.properties.id}-dimensionWithMarks-dasharray`}
                  labelText={Text({ textId: '@StyleStrokeDashArray' })}
                  inputKey='dashArray'
                  labelClassName=''
                  inputClassName=''
                  type='text'
                  value={props.properties.dimensionOptions.dimensionWithMarks.dashArray ?? ''}
                  onChange={(value) => { props.onChange('dashArray', value, PropertyType.DimensionWithMarks); }}/>
              </div>
            </>
          }
        </div>
      </Category>

      {props.properties.style !== undefined &&
        <Category category={{
          Type: 'Style',
          DisplayedText: Text({ textId: '@ContainerStyle' })
        }}
        heightClass={`${categoryHeight}`}
        >
          <div className='grid grid-cols-5 gap-6 items-center prop-category-body'>
            <InputGroup
              labelText={Text({ textId: '@StyleStroke' })}
              inputKey={`${props.properties.id}-stroke`}
              labelClassName='col-span-2'
              inputClassName='col-span-3'
              type='color'
              value={props.properties.style.stroke ?? '#000000'}
              onChange={(e) => { props.onChange('stroke', e.target.value, PropertyType.Style); }}/>
            <InputGroup
              labelKey={`${props.properties.id}-strokeOpacity`}
              labelText={Text({ textId: '@StyleStrokeOpacity' })}
              inputKey='strokeOpacity'
              labelClassName='col-span-2'
              inputClassName='col-span-3'
              type='range'
              min={0}
              max={1}
              step={0.01}
              value={(props.properties.style.strokeOpacity ?? 1).toString()}
              onChange={(event) => { props.onChange('strokeOpacity', Number(event.target.value), PropertyType.Style); }}
            />
            <TextInputGroup
              id={`${props.properties.id}-strokeWidth`}
              labelText={Text({ textId: '@StyleStrokeWidth' })}
              inputKey='strokeWidth'
              labelClassName='col-span-2'
              inputClassName='col-span-3'
              type='number'
              value={(props.properties.style.strokeWidth ?? 1).toString()}
              onChange={(value) => { props.onChange('strokeWidth', Number(value), PropertyType.Style); }}
            />
            <InputGroup
              labelText={Text({ textId: '@StyleFill' })}
              inputKey={`${props.properties.id}-fill`}
              labelClassName='col-span-2'
              inputClassName='col-span-3'
              type='color'
              value={props.properties.style.fill ?? '#000000'}
              onChange={(e) => { props.onChange('fill', e.target.value, PropertyType.Style); }}/>
            <InputGroup
              labelKey={`${props.properties.id}-fillOpacity`}
              labelText={Text({ textId: '@StyleFillOpacity' })}
              inputKey='fillOpacity'
              labelClassName='col-span-2'
              inputClassName='col-span-3'
              type='range'
              min={0}
              max={1}
              step={0.01}
              value={(props.properties.style.fillOpacity ?? 1).toString()}
              onChange={(event) => { props.onChange('fillOpacity', Number(event.target.value), PropertyType.Style); }}
            />
          </div>
        </Category>
      }
    </div>
  );
}
