export { Renderer, PropType, FElement, FElem, FNode, FChild } from "./renderer";
export { handle, get, handlers, EventBinder, Compilable } from "./catalyst";
export { stasis } from "./stasis";
import { Renderer, FElement, FElem, FSVGElement } from "./renderer";
import { handlers } from "./catalyst";
import { EMPTY } from "efreet/utils";

// Macros
declare global {
  export type PARRArray<T> = PARRLabel<T> & [any, ...(string | number)[]];
  export interface PARRLabel<T> {
    __type: T;
    slice(end?: number): PARRArray<T>;
    slice(start?: number, end?: number): PARRArray<T>;
  }
  function PARR<T>(x: T): PARRArray<T>;
}

let _renderer: Renderer | undefined;
if (typeof window !== "undefined") _renderer = new Renderer();

export let renderer = _renderer!;
let _handlers = handlers;

namespace React {
  export let renderer = _renderer!;
  export let handlers = _handlers;

  export function createElement(
    tagname:
      | string
      | ((
          props: FElement,
          children?: (string | FElement | FElement[] | undefined)[]
        ) => FElement),
    props?: FElement,
    ...children: (FElem | string | undefined)[]
  ): FElem {
    if (!props) props = { kind: "dynamic" };
    if (!props.kind) props.kind = "dynamic";

    if (children) {
      let _cleaned: (string | FElem | undefined)[] = [];
      for (let child of children) {
        if (child instanceof Array) _cleaned.push(...child);
        else _cleaned.push(child);
      }
      children = _cleaned;
    }

    if (props.svg) {
      if (props.xlinkHref) {
        props["xlink:href"] = props.xlinkHref;
        delete props.xlinkHref;
      }
    }

    let elem = props as FElem;
    if (typeof tagname === "function") elem = tagname(props, children) as FElem;
    else {
      elem.tagname = tagname;
      if (children) props.children = children;
    }

    return elem;
  }
}

declare global {
  namespace React {
    export let renderer: Renderer;
    export let handlers: typeof _handlers;
    export function createElement(
      tagname: string,
      props?: FElement,
      ...children: (FElem | string | undefined)[]
    ): FElem;
  }

  namespace JSX {
    // interface ElementAttributesProperty { props: {}; }
    interface ElementChildrenAttribute {
      children: {}; // specify children name to use
    }

    // interface Element extends FElement {}

    interface IntrinsicElements {
      [tag: string]: FElement;
      div: FElement;
      section: FElement;
      span: FElement;
      button: FElement;
      a: FElement;
      nav: FElement;
      ul: FElement;
      ol: FElement;
      li: FElement;
      input: FElement;
      textarea: FElement;

      // SVG
      svg: FSVGElement & {
        viewBox: string;
        height?: number | string;
        width?: number | string;
        preserveAspectRatio?: string;
        x?: number | string;
        y?: number | string;
      };

      g: FSVGElement;

      circle: FSVGElement & {
        cx: number | string;
        cy: number | string;
        r: number | string;
        pathLength?: number | string;
      };

      ellipse: FSVGElement & {
        cx: number | string;
        cy: number | string;
        rx: number | string;
        ry: number | string;
        pathLength?: number | string;
      };

      line: FSVGElement & {
        x1: number | string;
        y1: number | string;
        x2: number | string;
        y2: number | string;
        pathLength?: number | string;
      };

      polygon: FSVGElement & {
        points: string;
        pathLength?: number | string;
      };

      polyline: FSVGElement & {
        points: string;
        pathLength?: number | string;
      };

      path: FSVGElement & {
        d: string;
      };

      rect: FSVGElement & {
        x: number | string;
        y: number | string;
        width: number | string;
        height: number | string;
        rx?: number | string;
        ry?: number | string;
        pathLength?: number | string;
      };
    }
  }
}

if (typeof window !== "undefined") (window as any).React = React;
