import { Component, ReactElement } from 'react';
import { Icon } from '@alifd/next';
import classNames from 'classnames';
import { Title, observer, Tip, globalContext, Editor } from '@ali/lowcode-editor-core';
import { DockProps } from '../../types';
import PanelDock from '../../widget/panel-dock';
import { composeTitle } from '../../widget/utils';
import WidgetContainer from '../../widget/widget-container';
import Panel from '../../widget/panel';
import { IWidget } from '../../widget/widget';
import { SkeletonEvents } from '../../skeleton';

import './index.less';

export function DockView({ title, icon, description, size, className, onClick }: DockProps) {
  return (
    <Title
      title={composeTitle(title, icon, description)}
      className={classNames('lc-dock', className, {
        [`lc-dock-${size}`]: size,
      })}
      onClick={onClick}
    />
  );
}

function HelpTip({ tip }: any) {
  if (tip && tip.url) {
    return (
      <div>
        <a href={tip.url} target="_blank" rel="noopener noreferrer">
          <Icon type="help" size="small" className="lc-help-tip" />
        </a>
        <Tip>{tip.content}</Tip>
      </div>
    );
  }
  return (
    <div>
      <Icon type="help" size="small" className="lc-help-tip" />
      <Tip>{tip.content}</Tip>
    </div>
  );
}

@observer
export class PanelDockView extends Component<DockProps & { dock: PanelDock }> {
  componentDidMount() {
    this.checkActived();
  }

  componentDidUpdate() {
    this.checkActived();
  }

  private lastActived = false;

  checkActived() {
    const { dock } = this.props;
    if (dock.actived !== this.lastActived) {
      this.lastActived = dock.actived;
      if (this.lastActived) {
        dock.skeleton.postEvent(SkeletonEvents.PANEL_DOCK_ACTIVE, dock.name, dock);
      } else {
        dock.skeleton.postEvent(SkeletonEvents.PANEL_DOCK_UNACTIVE, dock.name, dock);
      }
    }
  }

  render() {
    const { dock, className, onClick, ...props } = this.props;
    return DockView({
      ...props,
      className: classNames(className, {
        actived: dock.actived,
      }),
      onClick: () => {
        onClick && onClick();
        dock.togglePanel();
      },
    });
  }
}

export class DialogDockView extends Component {}

@observer
export class TitledPanelView extends Component<{ panel: Panel; area?: string }> {
  shouldComponentUpdate() {
    return false;
  }

  componentDidMount() {
    this.checkVisible();
  }

  componentDidUpdate() {
    this.checkVisible();
  }

  private lastVisible = false;

  checkVisible() {
    const { panel } = this.props;
    const currentVisible = panel.inited && panel.visible;
    if (currentVisible !== this.lastVisible) {
      this.lastVisible = currentVisible;
      if (this.lastVisible) {
        panel.skeleton.postEvent(SkeletonEvents.PANEL_SHOW, panel.name, panel);
      } else {
        panel.skeleton.postEvent(SkeletonEvents.PANEL_HIDE, panel.name, panel);
      }
    }
  }

  render() {
    const { panel, area } = this.props;
    if (!panel.inited) {
      return null;
    }
    const editor = globalContext.get(Editor);
    const panelName = area ? `${area}-${panel.name}` : panel.name;
    editor?.emit('skeleton.panel.toggle', {
      name: panelName || '',
      status: panel.visible ? 'show' : 'hide',
    });
    return (
      <div
        className={classNames('lc-titled-panel', {
          hidden: !panel.visible,
        })}
        id={panelName}
      >
        <PanelTitle panel={panel} />
        <div className="lc-panel-body">{panel.body}</div>
      </div>
    );
  }
}

@observer
export class PanelView extends Component<{ panel: Panel; area?: string }> {
  shouldComponentUpdate() {
    return false;
  }

  componentDidMount() {
    this.checkVisible();
  }

  componentDidUpdate() {
    this.checkVisible();
  }

  private lastVisible = false;

  checkVisible() {
    const { panel } = this.props;
    const currentVisible = panel.inited && panel.visible;
    if (currentVisible !== this.lastVisible) {
      this.lastVisible = currentVisible;
      if (this.lastVisible) {
        panel.skeleton.postEvent(SkeletonEvents.PANEL_SHOW, panel.name, panel);
        // FIXME! remove this line
        panel.skeleton.postEvent('leftPanel.show' as any, panel.name, panel);
      } else {
        panel.skeleton.postEvent(SkeletonEvents.PANEL_HIDE, panel.name, panel);
        // FIXME! remove this line
        panel.skeleton.postEvent('leftPanel.hide' as any, panel.name, panel);
      }
    }
  }

  render() {
    const { panel, area } = this.props;
    if (!panel.inited) {
      return null;
    }
    const editor = globalContext.get(Editor);
    const panelName = area ? `${area}-${panel.name}` : panel.name;
    editor?.emit('skeleton.panel.toggle', {
      name: panelName || '',
      status: panel.visible ? 'show' : 'hide',
    });
    return (
      <div
        className={classNames('lc-panel', {
          hidden: !panel.visible,
        })}
        id={panelName}
      >
        {panel.body}
      </div>
    );
  }
}

@observer
export class TabsPanelView extends Component<{ container: WidgetContainer<Panel> }> {
  render() {
    const { container } = this.props;
    const titles: ReactElement[] = [];
    const contents: ReactElement[] = [];
    container.items.forEach((item: any) => {
      titles.push(<PanelTitle key={item.id} panel={item} className="lc-tab-title" />);
      contents.push(<PanelView key={item.id} panel={item} />);
    });

    return (
      <div className="lc-tabs">
        <div
          className="lc-tabs-title"
          onClick={(e) => {
            const shell = e.currentTarget;
            const t = e.target as Element;
            let elt = shell.firstElementChild;
            while (elt) {
              if (elt.contains(t)) {
                break;
              }
              elt = elt.nextElementSibling;
            }
            if (elt) {
              container.active((elt as any).dataset.name);
            }
          }}
        >
          {titles}
        </div>
        <div className="lc-tabs-content">{contents}</div>
      </div>
    );
  }
}

@observer
class PanelTitle extends Component<{ panel: Panel; className?: string }> {
  render() {
    const { panel, className } = this.props;
    return (
      <div
        className={classNames('lc-panel-title', className, {
          actived: panel.actived,
        })}
        data-name={panel.name}
      >
        <Title title={panel.title || panel.name} />
        {panel.help ? <HelpTip tip={panel.help} /> : null}
      </div>
    );
  }
}

@observer
export class WidgetView extends Component<{ widget: IWidget }> {
  shouldComponentUpdate() {
    return false;
  }

  componentDidMount() {
    this.checkVisible();
  }

  componentDidUpdate() {
    this.checkVisible();
  }

  private lastVisible = false;

  checkVisible() {
    const { widget } = this.props;
    const currentVisible = widget.visible;
    if (currentVisible !== this.lastVisible) {
      this.lastVisible = currentVisible;
      if (this.lastVisible) {
        widget.skeleton.postEvent(SkeletonEvents.WIDGET_SHOW, widget.name, widget);
      } else {
        widget.skeleton.postEvent(SkeletonEvents.WIDGET_SHOW, widget.name, widget);
      }
    }
  }

  render() {
    const { widget } = this.props;
    if (!widget.visible) {
      return null;
    }
    return widget.body;
  }
}
