import React from 'react';
import { ScopedContext, IScopedContext } from '../../../../Scoped';
import { Renderer, RendererProps } from '../../../../factory';
import { SchemaNode, Schema, Action } from '../../../../types';
import { default as ChildViewWrapper } from './ChildViewWrapper';
import findLast from 'lodash/findLast';
import {
  guid,
  isVisible,
  autobind,
  isObjectShallowModified
} from '../../../../utils/helper';
import { reaction } from 'mobx';
import { Icon } from '../../../../components/icons';
import { findDOMNode } from 'react-dom';
import { IModalStore, ModalStore } from '../../../../store/modal';
import { filter } from '../../../../utils/tpl';
import { Spinner } from '../../../../components';
import { IServiceStore } from '../../../../store/service';
import {
  BaseSchema,
  SchemaClassName,
  SchemaCollection,
  SchemaName
} from '../../../../Schema';
import { BreadcrumbSchema } from '../../../Breadcrumb';
import { isAlive } from 'mobx-state-tree';

/**
 * ChildView 新的子页面
 */
export interface ChildViewSchema extends BaseSchema {
  type: 'lion-child-view';

  /**
   * 内容区域
   */
  body?: SchemaCollection;

  /**
   * 配置 Body 容器 className
   */
  bodyClassName?: SchemaClassName;

  name?: SchemaName;


  /**
   * 影响自动生成的按钮，如果自己配置了按钮这个配置无效。
   */
  confirm?: boolean;

  /**
   * 配置导航面包屑
   */
  breadcrumb?: BreadcrumbSchema;

}

export type ChildViewSchemaBase = Omit<ChildViewSchema, 'type'>;

export interface ChildViewProps
  extends RendererProps,
  Omit<ChildViewSchema, 'className'> {
  onClose: () => void;
  onConfirm: (
    values: Array<object>,
    action: Action,
    ctx: object,
    targets: Array<any>
  ) => void;
  children?: React.ReactNode | ((props?: any) => React.ReactNode);
  wrapperComponent: React.ElementType;
  lazySchema?: (props: ChildViewProps) => SchemaCollection;
  store: IModalStore;
  show?: boolean;
  modalContainer?: string;
}

export interface ChildViewState {
  entered: boolean;
  [propName: string]: any;
}

export default class ChildView extends React.Component<ChildViewProps> {
  static propsList: Array<string> = [
    'children',
    'bodyClassName',
    'confirm',
    'onClose',
    'onConfirm',
    'show',
    'body',
    'popOverContainer',
  ];
  static defaultProps: Partial<ChildViewProps> = {
    bodyClassName: '',
    confirm: true,
  };

  reaction: any;
  $$id: string = guid();
  lionChildView: any;

  constructor(props: ChildViewProps) {
    super(props);

    props.store.setEntered(!!props.show);
    this.handleSelfClose = this.handleSelfClose.bind(this);
    this.handleAction = this.handleAction.bind(this);
    this.handleDrawerConfirm = this.handleDrawerConfirm.bind(this);
    this.handleDrawerClose = this.handleDrawerClose.bind(this);
    this.handleDialogConfirm = this.handleDialogConfirm.bind(this);
    this.handleDialogClose = this.handleDialogClose.bind(this);
    this.handleChildFinished = this.handleChildFinished.bind(this);
    this.handleEntered = this.handleEntered.bind(this);
    this.handleExited = this.handleExited.bind(this);
    this.handleFormInit = this.handleFormInit.bind(this);
    this.handleFormChange = this.handleFormChange.bind(this);
    this.handleFormSaved = this.handleFormSaved.bind(this);

    const store = props.store;
    this.reaction = reaction(
      () => `${store.loading}${store.error}`,
      () => this.forceUpdate()
    );



    // this.state = {
    //   targetContainer : document.querySelector('.antd-Page')
    // }
  }

  // shouldComponentUpdate(nextProps:ChildViewProps) {
  //     const props = this.props;

  //     if (props.show === nextProps.show && !nextProps.show) {
  //         return false;
  //     }

  //     return isObjectShallowModified(this.props, nextProps);
  // }
  componentWillMount() {
  }

  componentWillUnmount() {
    this.reaction && this.reaction();
  }

  handleSelfClose() {
    const { onClose, store } = this.props;

    // 如果有子弹框，那么就先不隐藏自己
    if (store.dialogOpen !== false || store.drawerOpen !== false) {
      return;
    }

    // clear error
    store.updateMessage();
    onClose();
  }

  handleAction(e: React.UIEvent<any>, action: Action, data: object) {
    const { onClose, onAction } = this.props;
    if (action.actionType === 'close' || action.actionType === 'cancel') {
      onClose();
    } else if (onAction) {
      onAction(e, action, data);
    }
  }

  handleDrawerConfirm(values: object[], action: Action, ...args: Array<any>) {
    const { store } = this.props;

    if (action.mergeData && values.length === 1 && values[0]) {
      store.updateData(values[0]);
    }

    const drawerAction = store.action as Action;
    const drawer = drawerAction.drawer as any;

    if (
      drawer.onConfirm &&
      drawer.onConfirm(values, action, ...args) === false
    ) {
      return;
    }

    store.closeDrawer();
  }

  handleDrawerClose(...args: Array<any>) {
    const { store } = this.props;

    const action = store.action as Action;
    const drawer = action.drawer as any;

    if (drawer.onClose && drawer.onClose(...args) === false) {
      return;
    }

    store.closeDrawer();
  }

  handleDialogConfirm(values: object[], action: Action, ...args: Array<any>) {
    const { store } = this.props;

    if (action.mergeData && values.length === 1 && values[0]) {
      store.updateData(values[0]);
    }

    const dialogAction = store.action as Action;
    const dialog = dialogAction.dialog as any;

    if (
      dialog.onConfirm &&
      dialog.onConfirm(values, action, ...args) === false
    ) {
      return;
    }

    store.closeDialog();
  }

  handleDialogClose(...args: Array<any>) {
    const { store } = this.props;

    const action = store.action as Action;
    const dialog = action.dialog as any;

    if (dialog.onClose && dialog.onClose(...args) === false) {
      return;
    }

    store.closeDialog();
  }

  handleChildFinished(value: any, action: Action) {
    // 下面会覆盖
  }

  handleFormInit(data: any) {
    const { store } = this.props;

    store.setFormData(data);
  }

  handleFormChange(data: any, name?: string) {
    const { store } = this.props;

    if (typeof name === 'string') {
      data = {
        [name]: data
      };
    }

    store.setFormData(data);
  }

  handleFormSaved(data: any, response: any) {
    const { store } = this.props;

    store.setFormData({
      ...data,
      ...response
    });
  }

  handleEntered() {
    const { lazySchema, store } = this.props;

    store.setEntered(true);
    if (typeof lazySchema === 'function') {
      store.setSchema(lazySchema(this.props));
    }
  }

  handleExited() {
    const { lazySchema, store } = this.props;
    if (isAlive(store)) {
      store.reset();
      store.setEntered(false);
      if (typeof lazySchema === 'function') {
        store.setSchema('');
      }
    }
  }

  @autobind
  getPopOverContainer() {
    return (findDOMNode(this) as HTMLElement).querySelector(
      `.${this.props.classPrefix}Drawer-content`
    );
  }

  renderBody(body: SchemaNode, key?: any): React.ReactNode {
    let { render, store } = this.props;

    if (Array.isArray(body)) {
      return body.map((body, key) => this.renderBody(body, key));
    }

    let schema: Schema = body as Schema;
    let subProps: any = {
      key,
      disabled: store.loading,
      onAction: this.handleAction,
      onFinished: this.handleChildFinished,
      popOverContainer: this.getPopOverContainer,
      onChange: this.handleFormChange,
      onInit: this.handleFormInit,
      onSaved: this.handleFormSaved
    };

    if (schema.type === 'form') {
      schema = {
        mode: 'horizontal',
        wrapWithPanel: false,
        submitText: null,
        ...schema
      };
    }

    return render(`body${key ? `/${key}` : ''}`, schema, subProps);
  }

  openFeedback(dialog: any, ctx: any) {
    return new Promise(resolve => {
      const { store } = this.props;
      store.setCurrentAction({
        type: 'button',
        actionType: 'dialog',
        dialog: dialog
      });
      store.openDialog(ctx, undefined, confirmed => {
        resolve(confirmed);
      });
    });
  }

  render() {
    const store = this.props.store;
    const {
      className,
      closeOnEsc,
      render,
      body,
      bodyClassName,
      show,
      wrapperComponent,
      env,
      classPrefix: ns,
      classnames: cx,
      modalContainer,
      breadcrumb
    } = {
      ...this.props,
      ...store.schema
    } as any;

    const Container = wrapperComponent || ChildViewWrapper;
    const targetContainer = modalContainer && document.querySelector(modalContainer)
    // const targetContainer = document.querySelector('.antd-Page')
    // const targetContainer = ''


    return (
      <Container
        classPrefix={ns}
        className={className}
        onHide={this.handleSelfClose}
        disabled={store.loading}
        show={show}
        onEntered={this.handleEntered}
        onExited={this.handleExited}
        container={
          targetContainer
            ? targetContainer
            : env && env.getModalContainer
              ? env.getModalContainer
              : undefined
        }
      >
        <div className={`${ns}lionChildView-header`}>
          <div className={`${ns}lionChildView-back`} onClick={this.handleSelfClose}>
            <Icon icon="back" className="icon" />
            <span className="text">返回</span>
          </div>
          {
            breadcrumb 
              ?(<>
                <div className={"line"}></div>
                <div className={`${ns}lionChildView-breadcrumb`}>
                  {render('breadcrumb', {
                    ...breadcrumb,
                    "type": "breadcrumb"
                  })}
                </div>
              </>) 
              :null
          }
        </div>

        {!store.entered ? (
          <div className={cx('lionChildView-body', bodyClassName)}>
            <Spinner overlay show size="lg" />
          </div>
        ) : body ? (
          <div className={cx('lionChildView-body', bodyClassName)}>
            {this.renderBody(body, 'body')}
          </div>
        ) : null}

        {/* {
         body ? (
            <div className={cx('lionChildView-body', bodyClassName)}>
              {this.renderBody(body, 'body')}
            </div>
          ) : null
        }  */}


        {body
          ? render(
            'dialog',
            {
              ...((store.action as Action) &&
                ((store.action as Action).dialog as object)),
              type: 'dialog'
            },
            {
              key: 'dialog',
              data: store.dialogData,
              onConfirm: this.handleDialogConfirm,
              onClose: this.handleDialogClose,
              onAction: this.handleAction,
              show: store.dialogOpen
            }
          )
          : null}

        {body
          ? render(
            'drawer',
            {
              ...((store.action as Action) &&
                ((store.action as Action).drawer as object)),
              type: 'drawer'
            },
            {
              key: 'drawer',
              data: store.drawerData,
              onConfirm: this.handleDrawerConfirm,
              onClose: this.handleDrawerClose,
              onAction: this.handleAction,
              show: store.drawerOpen
            }
          )
          : null}

        {body
          ? render(
            'lion-child-view',
            {
              ...((store.action as Action) &&
                ((store.action as Action).lionChildView as object)),
              type: 'lion-child-view'
            },
            {
              key: 'lion-child-view',
              data: store.lionChildViewData,
              onClose: store.closeLionChildView,
              show: store.lionChildViewOpen
            }
          )
          : null}

      </Container>
    );
  }
}

@Renderer({
  type: 'lion-child-view',
  storeType: ModalStore.name,
  storeExtendsData: false,
  isolateScope: true,
  shouldSyncSuperStore: (store: IServiceStore, props: any, prevProps: any) =>
    !!(
      (store.lionChildViewOpen || props.show) &&
      (props.show !== prevProps.show ||
        isObjectShallowModified(prevProps.data, props.data))
    )
})
export class ChildViewRenderer extends ChildView {
  static contextType = ScopedContext;

  constructor(props: ChildViewProps, context: IScopedContext) {
    super(props);
    const scoped = context;

    scoped.registerComponent(this);
  }

  componentWillUnmount() {
    const scoped = this.context as IScopedContext;
    scoped.unRegisterComponent(this);
    super.componentWillUnmount();
  }

  tryChildrenToHandle(action: Action, ctx: object, rawAction?: Action) {
    const scoped = this.context as IScopedContext;

    if (action.fromDialog) {
      return false;
    }

    const targets: Array<any> = [];
    const { onConfirm, store } = this.props;

    if (action.target) {
      targets.push(
        ...action.target
          .split(',')
          .map(name => scoped.getComponentByName(name))
          .filter(item => item && item.doAction)
      );
    }

    if (!targets.length) {
      let components = scoped
        .getComponents()
        .filter(item => !~['drawer', 'dialog'].indexOf(item.props.type));

      const pool = components.concat();

      while (pool.length) {
        const item = pool.pop()!;

        if (~['crud', 'form', 'wizard'].indexOf(item.props.type)) {
          targets.push(item);
          break;
        } else if (~['drawer', 'dialog'].indexOf(item.props.type)) {
          continue;
        } else if (~['page', 'service'].indexOf(item.props.type)) {
          pool.unshift.apply(pool, item.context.getComponents());
        }
      }
    }

    if (targets.length) {
      store.markBusying(true);
      store.updateMessage();

      Promise.all(
        targets.map(target =>
          target.doAction(
            {
              ...action,
              from: this.$$id
            },
            ctx,
            true
          )
        )
      )
        .then(values => {
          if (
            (action.type === 'submit' ||
              action.actionType === 'submit' ||
              action.actionType === 'confirm') &&
            action.close !== false
          ) {
            onConfirm && onConfirm(values, rawAction || action, ctx, targets);
          } else if (action.close) {
            action.close === true
              ? this.handleSelfClose()
              : this.closeTarget(action.close);
          }
          store.markBusying(false);
        })
        .catch(reason => {
          store.updateMessage(reason.message, true);
          store.markBusying(false);
        });

      return true;
    }

    return false;
  }

  handleAction(
    e: React.UIEvent<any>,
    action: Action,
    data: object,
    throwErrors: boolean = false,
    delegate?: IScopedContext
  ) {
    const { onClose, onAction, store, env } = this.props;

    if (action.from === this.$$id) {
      return onAction
        ? onAction(e, action, data, throwErrors, delegate || this.context)
        : false;
    }

    const scoped = this.context as IScopedContext;

    if (action.actionType === 'close' || action.actionType === 'cancel') {
      store.setCurrentAction(action);
      onClose();
      action.close && this.closeTarget(action.close);
    } else if (action.actionType === 'confirm') {
      store.setCurrentAction(action);
      this.tryChildrenToHandle(action, data) || onClose();
    } else if (action.actionType === 'drawer') {
      store.setCurrentAction(action);
      store.openDrawer(data);
    } else if (action.actionType === 'dialog') {
      store.setCurrentAction(action);
      store.openDialog(data);
    } else if (action.actionType === 'reload') {
      store.setCurrentAction(action);
      action.target && scoped.reload(action.target, data);
      if (action.close) {
        this.handleSelfClose();
        this.closeTarget(action.close);
      }
    } else if (this.tryChildrenToHandle(action, data)) {
      // do nothing
    } else if (action.actionType === 'ajax') {
      store.setCurrentAction(action);
      store
        .saveRemote(action.api as string, data, {
          successMessage: action.messages && action.messages.success,
          errorMessage: action.messages && action.messages.failed
        })
        .then(async () => {
          if (action.feedback && isVisible(action.feedback, store.data)) {
            await this.openFeedback(action.feedback, store.data);
          }

          const redirect =
            action.redirect && filter(action.redirect, store.data);
          redirect && env.jumpTo(redirect, action);
          action.reload && this.reloadTarget(action.reload, store.data);
          if (action.close) {
            this.handleSelfClose();
            this.closeTarget(action.close);
          }
        })
        .catch(() => { });
    } else if (onAction) {
      let ret = onAction(
        e,
        action,
        data,
        throwErrors,
        delegate || this.context
      );
      action.close &&
        (ret && ret.then
          ? ret.then(this.handleSelfClose)
          : setTimeout(this.handleSelfClose, 200));
    }
  }

  handleChildFinished(value: any, action: Action) {
    if ((action && action.from === this.$$id) || action.close === false) {
      return;
    }

    const scoped = this.context as IScopedContext;
    const components = scoped
      .getComponents()
      .filter((item: any) => !~['drawer', 'dialog'].indexOf(item.props.type));
    const onConfirm = this.props.onConfirm;

    if (
      components.length === 1 &&
      (components[0].props.type === 'form' ||
        components[0].props.type === 'wizard')
    ) {
      onConfirm([value], action, {}, components);
    }
  }

  handleDialogConfirm(values: object[], action: Action, ...rest: Array<any>) {
    super.handleDialogConfirm(values, action, ...rest);
    const scoped = this.context as IScopedContext;
    const store = this.props.store;
    const dialogAction = store.action as Action;
    const reload = action.reload ?? dialogAction.reload;

    if (reload) {
      scoped.reload(reload, store.data);
    } else {
      // 没有设置，则自动让页面中 crud 刷新。
      scoped
        .getComponents()
        .filter((item: any) => item.props.type === 'crud')
        .forEach((item: any) => item.reload && item.reload());
    }
  }

  handleDrawerConfirm(values: object[], action: Action, ...rest: Array<any>) {
    super.handleDrawerConfirm(values, action);
    const scoped = this.context as IScopedContext;
    const store = this.props.store;
    const drawerAction = store.action as Action;

    // 稍等会，等动画结束。
    setTimeout(() => {
      if (drawerAction.reload) {
        scoped.reload(drawerAction.reload, store.data);
      } else if (action.reload) {
        scoped.reload(action.reload, store.data);
      } else {
        // 没有设置，则自动让页面中 crud 刷新。
        scoped
          .getComponents()
          .filter((item: any) => item.props.type === 'crud')
          .forEach((item: any) => item.reload && item.reload());
      }
    }, 300);
  }

  reloadTarget(target: string, data?: any) {
    const scoped = this.context as IScopedContext;
    scoped.reload(target, data);
  }

  closeTarget(target: string) {
    const scoped = this.context as IScopedContext;
    scoped.close(target);
  }
}
