import * as React from 'react';
import { XPositionReference } from '../../../Enums/XPositionReference';
import { IContainerModel } from '../../../Interfaces/IContainerModel';
import { DIMENSION_MARGIN } from '../../../utils/default';
import { getDepth } from '../../../utils/itertools';
import { Dimension } from './Dimension';

interface IContainerProps {
  model: IContainerModel
}

/**
 * Render the container
 * @returns Render the container
 */
export const Container: React.FC<IContainerProps> = (props: IContainerProps) => {
  const containersElements = props.model.children.map(child => <Container key={`container-${child.properties.id}`} model={child} />);
  const xText = props.model.properties.width / 2;
  const yText = props.model.properties.height / 2;

  const [transformedX, transformedY] = transformPosition(
    props.model.properties.x,
    props.model.properties.y,
    props.model.properties.width,
    props.model.properties.XPositionReference
  );
  const transform = `translate(${transformedX}, ${transformedY})`;

  // g style
  const defaultStyle: React.CSSProperties = {
    transitionProperty: 'all',
    transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)',
    transitionDuration: '150ms'
  };

  // Rect style
  const style = Object.assign(
    JSON.parse(JSON.stringify(defaultStyle)),
    props.model.properties.style
  );

  // Dimension props
  const depth = getDepth(props.model);
  const dimensionMargin = DIMENSION_MARGIN * (depth + 1);
  const id = `dim-${props.model.properties.id}`;
  const xStart: number = 0;
  const xEnd = props.model.properties.width;
  const y = -dimensionMargin;
  const strokeWidth = 1;
  const text = (props.model.properties.width ?? 0).toString();

  let dimensionChildren: JSX.Element | null = null;
  if (props.model.children.length > 0) {
    const {
      childrenId,
      xChildrenStart,
      xChildrenEnd,
      yChildren,
      textChildren
    } = GetChildrenDimensionProps(props, dimensionMargin);
    dimensionChildren = <Dimension
      id={childrenId}
      xStart={xChildrenStart}
      xEnd={xChildrenEnd}
      yStart={yChildren}
      yEnd={yChildren}
      strokeWidth={strokeWidth}
      text={textChildren}
    />;
  }

  return (
    <g
      style={defaultStyle}
      transform={transform}
      key={`container-${props.model.properties.id}`}
    >
      <Dimension
        id={id}
        xStart={xStart}
        xEnd={xEnd}
        yStart={y}
        yEnd={y}
        strokeWidth={strokeWidth}
        text={text}
      />
      { dimensionChildren }
      <rect
        width={props.model.properties.width}
        height={props.model.properties.height}
        style={style}
      >
      </rect>
      <text
        x={xText}
        y={yText}
      >
        {props.model.properties.id}
      </text>
      { containersElements }
    </g>
  );
};

function GetChildrenDimensionProps(props: IContainerProps, dimensionMargin: number):
{ childrenId: string, xChildrenStart: number, xChildrenEnd: number, yChildren: number, textChildren: string } {
  const childrenId = `dim-children-${props.model.properties.id}`;

  const lastChild = props.model.children[props.model.children.length - 1];
  let xChildrenStart = lastChild.properties.x;
  let xChildrenEnd = lastChild.properties.x + lastChild.properties.width;
  for (let i = props.model.children.length - 2; i >= 0; i--) {
    const child = props.model.children[i];
    const left = child.properties.x;
    if (left < xChildrenStart) {
      xChildrenStart = left;
    }
    const right = child.properties.x + child.properties.width;
    if (right > xChildrenEnd) {
      xChildrenEnd = right;
    }
  }

  const yChildren = props.model.properties.height + dimensionMargin;
  const textChildren = (xChildrenEnd - xChildrenStart).toString();
  return { childrenId, xChildrenStart, xChildrenEnd, yChildren, textChildren };
}

export function transformPosition(x: number, y: number, width: number, xPositionReference = XPositionReference.Left): [number, number] {
  let transformedX = x;
  if (xPositionReference === XPositionReference.Center) {
    transformedX -= width / 2;
  } else if (xPositionReference === XPositionReference.Right) {
    transformedX -= width;
  }
  return [transformedX, y];
}
