import {useCallback, Fragment} from 'react';
import {v4 as uuidv4} from 'uuid';
import {Editor, StringField, NumberField, OverlayHandle} from './Editor';

import type {SvgItem} from './App';
import type {Action} from './Editor';

export type Circle = {
  type: 'circle',
  id: string,
  stroke: string,
  strokeWidth: number,
  cx: number,
  cy: number,
  r: number,
}

type CircleRenderProps = {
  circle: Circle,
}

export function CircleRender({circle}: CircleRenderProps) {
  return <circle
    cx={circle.cx}
    cy={circle.cy}
    r={circle.r}
    stroke={circle.stroke}
    strokeWidth={circle.strokeWidth}
    fill="none" />;
}

export function CircleOverlaySVG({circle}: CircleRenderProps) {
  return <path
    d={`M${circle.cx} ${circle.cy} L${circle.cx + circle.r} ${circle.cy}`}
    stroke="grey"
    strokeWidth={circle.strokeWidth}
    strokeDasharray="2 1" />;
}

type CircleEditorProps = {
  circle: Circle,
  onChange: Action<SvgItem>,
}

export function CircleEditor({circle, onChange}: CircleEditorProps) {
  const onCxChange = useCallback((cx: number) => {
    onChange((item) => {
      if (item.type !== 'circle') {
        return item;
      }
      return {
        ...item,
        cx,
      };
    });
  }, [onChange]);
  const onCyChange = useCallback((cy: number) => {
    onChange((item) => {
      if (item.type !== 'circle') {
        return item;
      }
      return {
        ...item,
        cy,
      };
    });
  }, [onChange]);
  const onRChange = useCallback((r: number) => {
    onChange((item) => {
      if (item.type !== 'circle') {
        return item;
      }
      return {
        ...item,
        r,
      };
    });
  }, [onChange]);
  const onStrokeChange = useCallback((stroke: string) => {
    onChange((item) => {
      if (item.type !== 'circle') {
        return item;
      }
      return {
        ...item,
        stroke,
      };
    });
  }, [onChange]);
  const onStrokeWidthChange = useCallback((strokeWidth: number) => {
    onChange((item) => {
      if (item.type !== 'circle') {
        return item;
      }
      return {
        ...item,
        strokeWidth,
      };
    });
  }, [onChange]);

  return <Editor tag="circle">
    <NumberField name="cx" value={circle.cx} onChange={onCxChange} step={0.1} />
    <NumberField name="cy" value={circle.cy} onChange={onCyChange} step={0.1} />
    <NumberField name="r" value={circle.r} onChange={onRChange} step={0.1} />
    <StringField name="stroke" value={circle.stroke} onChange={onStrokeChange} />
    <NumberField name="stroke-width" value={circle.strokeWidth} onChange={onStrokeWidthChange} step={0.1} />
  </Editor>;
}

type CircleOverlayDOMProps = {
  circle: Circle,
  width: number,
  height: number,
  onChange: Action<SvgItem>,
}

export function CircleOverlayDOM({circle, width, height, onChange}: CircleOverlayDOMProps) {
  const onCChange = useCallback((cx: number, cy: number) => {
    onChange((item) => {
      if (item.type !== 'circle') {
        return item;
      }
      return {
        ...item,
        cx,
        cy,
      };
    });
  }, [ onChange]);
  const onRChange = useCallback((rx: number, ry: number) => {
    onChange((item) => {
      if (item.type !== 'circle') {
        return item;
      }
      const r = Math.sqrt((rx - circle.cx) * (rx - circle.cx) + (ry - circle.cy) * (ry - circle.cy));
      return {
        ...item,
        r,
      };
    });
  }, [onChange]);

  return <Fragment>
    <OverlayHandle x={circle.cx} y={circle.cy} width={width} height={height} onChange={onCChange} />
    <OverlayHandle x={circle.cx + circle.r} y={circle.cy} width={width} height={height} onChange={onRChange} />
  </Fragment>;
}

export function normalizeCircle(circle: any): Circle | null {
  if (!circle) {
    return null;
  }
  return {
    type: 'circle',
    id: typeof circle.id === 'string' ? circle.id : uuidv4(),
    cx: typeof circle.cx === 'number' ? circle.cx : 0,
    cy: typeof circle.cy === 'number' ? circle.cy : 0,
    r: typeof circle.r === 'number' ? circle.r : 0,
    stroke: typeof circle.stroke === 'string' ? circle.stroke : 'black',
    strokeWidth: typeof circle.strokeWidth === 'number' ? circle.strokeWidth : 0,
  };
}
