/**
 * Created at 2018/2/27.
 * @Author Ling.
 * @Email i@zeroling.com
 */
import React, { Component } from 'react';
import IceContainer from '@icedesign/container';

import axios from 'axios';
import {
  Input,
  Feedback,
  Select,
  Balloon,
  Icon,
  Button,
  Grid,
  Tab,
} from '@icedesign/base';
import Events from '@ali/ice-events';
import { Link } from 'react-router';
import TagGroup from './TagGroup';
import { prettierReady, isAlibaba, getUserInfo } from '../../utils';
import PlaygroundPreview from '../../components/PlaygroundPreview';
import MonacoEditor from './MonacoEditor';
import Loading from '../../components/Loading';
import { jsx as defaultJsx, scss as defaultScss } from './defaultCode';
import './Playground.scss';

const { Row, Col } = Grid;

const PREVIEW_TYPE_KEY = 'ice-playground-preview-type';

@Events
export default class extends Component {
  constructor(props) {
    super(props);
    this.userInfo = getUserInfo();
    this.queryId = props.params.playgroundId || null;
    const previewMode =
      window.localStorage.getItem(PREVIEW_TYPE_KEY) || 'context';

    const defaultCode = {
      jsx: defaultJsx,
      scss: defaultScss,
    };
    const fromDemo = /from=demo/.test(props.router.location.search);
    if (fromDemo) {
      try {
        const TRANSFER_KEY = 'ice:demo-box-transfer-to-playground';
        const str = window.localStorage.getItem(TRANSFER_KEY);
        const demo = JSON.parse(str);
        defaultCode.jsx = demo.jsx;
        defaultCode.scss = demo.scss;
        defaultCode.title = demo.title;
        window.localStorage.removeItem(TRANSFER_KEY);
      } catch (err) {}
    }

    if (/\d+/.test(this.queryId)) {
      defaultCode.jsx = '';
      defaultCode.scss = '';
    }

    this.state = {
      title: '',
      ...defaultCode,
      previewMode,
      tags: ['问题复现'],
      isLoading: this.queryId !== null && this.queryId !== 'new',
    };
  }

  componentDidMount() {
    window.addEventListener('keydown', this.handleCtrlS);

    this.on('editor:onChange', ({ type, code }) => {
      console.log('editor, oncahnge,', {type, code});
      if (type === 'jsx') {
        this.setState({ jsx: code });
      }
      if (type === 'scss') {
        this.setState({ scss: code });
      }
    });

    if (isAlibaba && this.queryId !== null) {
      if (!this.userInfo.hasLogin) {
        Feedback.toast.error('请先登录，3s 后自动刷新');
        setTimeout(() => {
          this.userInfo.login();
        }, 1e3);
      } else if (this.queryId !== 'new') {
        this.updatePlaygroundDataById(this.queryId);
      }
    }
  }
  componentWillUnmount() {
    window.removeEventListener('keydown', this.handleCtrlS);
  }

  handleCtrlS = (evt) => {
    if (evt.keyCode === 83 && (evt.ctrlKey || evt.metaKey)) {
      evt.stopPropagation();
      evt.preventDefault();
      this.save();
    }
  };

  updatePlaygroundDataById = (id) => {
    return axios
      .get('/api/demo/' + id)
      .then((response) => {
        const { status, data } = response;
        if (status !== 200 || !data || !data.status === 'success') {
          throw new Error('数据异常');
        } else {
          return data.data;
        }
      })
      .then((data) => {
        const { tags, id, title, sourceCode, style, updated_at } = data;
        this.setState({
          jsx: sourceCode,
          scss: style || '',
          title,
          tags,
          isLoading: false,
        });
        return data;
      })
      .catch((err) => {
        Feedback.toast.error(err.message);
      });
  };

  changePreviewMode = (type) => {
    this.setState({ previewMode: type }, () => {
      window.localStorage.setItem(PREVIEW_TYPE_KEY, type);
    });
  };

  formatCode = () => {
    if (!window.editors) {
      return;
    }
    prettierReady().then((prettier) => {
      window.editors.forEach(({ editor, id, type }) => {
        if (type === 'scss') {
          return;
        }
        try {
          const code = editor.getValue();
          const formattedCode = prettier.format(code || '', {
            singleQuote: true, // prefer 单引号
            trailingComma: 'es5', // 追加末尾逗号
            printWidth: 60
          });
          // 下面这个操作会触发 editor 的 onChange 从而触发本组件的 setState
          editor.setValue(formattedCode);
        } catch (err) {
          if (err instanceof SyntaxError || err.name === 'SyntaxError') {
            Feedback.toast.error('语法错误：' + err.message);
          } else {
            Feedback.toast.error('格式化错误：' + err.message);
          }
        }
      });
    });
  };

  checkForm = () => {
    const { title, tags } = this.state;
    if (!title) {
      return Promise.reject(new Error('标题需要填写'));
    }
    if (tags.length < 1) {
      return Promise.reject(new Error('至少选择一个标签'));
    }

    return new Promise((resolve) => {
      setTimeout(resolve, 1000);
    });
  };

  save = () => {
    this.setState({ saving: true });
    this.checkForm()
      .then(() => {
        const { tags, title, jsx, scss } = this.state;
        if (this.queryId !== null && this.queryId !== 'new') {
          // edit
          const data = {
            title,
            sourceCode: jsx,
            creator: this.userInfo.username,
            style: scss,
            tags,
            compilerCode: '',
            styleType: 'scss',
          };

          return axios.post(`/api/demo/${this.queryId}`, data);
        } else if (this.queryId === 'new') {
          // create
          const data = {
            title,
            sourceCode: jsx,
            creator: this.userInfo.username,
            style: scss,
            tags,
            compilerCode: '',
            styleType: 'scss',
          };

          return axios.post('/api/demo/create', data);
        }
      })
      .then((response) => {
        if (response.status !== 200 || response.data.status !== 'success') {
          throw new Error('保存出错! 可以向 卓凌 反馈。');
        } else {
          Feedback.toast.success('保存成功!');
          this.setState({ saving: false });
          if (response.data.id) {
            this.props.router.replace(`/playground/${response.data.id}`);
          }
        }
      })
      .catch((err) => {
        this.setState({ saving: false });
        Feedback.toast.error(err.message);
      });
  };

  render() {
    const {
      jsx,
      scss,
      previewMode,
      title,
      isLoading,
      saving,
      tags,
    } = this.state;
    const tagList = [
      {
        value: '问题复现',
      },
      {
        value: 'demo 演示',
      },
      {
        value: '组件封装',
        disabled: !this.userInfo.isAdmin,
      },
      {
        value: '常用布局',
        disabled: !this.userInfo.isAdmin,
      },
    ];
    return (
      <IceContainer className="playground-container">
        <div
          style={{
            display: 'flex',
            flexDirection: 'row',
            alignItems: 'center',
          }}
        >
          <div>
            <label>标题</label>
            <Input
              style={{ margin: '0 15px 0 10px' }}
              value={title}
              onChange={(title) => {
                this.setState({ title });
              }}
            />
          </div>
          <TagGroup
            dataSource={tagList}
            value={tags}
            onChange={(value) => {
              this.setState({ tags: value });
            }}
          />
        </div>
        <Row wrap style={{ width: '100%', paddingLeft: 0 }}>
          <Col xxs={24} s={12} l={12}>
            {isLoading ? (
              <Loading />
            ) : (
              <Tab
                size="small"
                tabBarExtraContent={
                  <span>
                    {isAlibaba && (
                      <Link to="/playground">
                        <Button size="small" style={{ marginRight: '15px' }}>
                          返回
                        </Button>
                      </Link>
                    )}
                    <Button
                      size="small"
                      onClick={this.formatCode}
                      style={{ marginRight: '15px' }}
                    >
                      代码格式化
                    </Button>
                    {isAlibaba && (
                      <Button
                        loading={saving}
                        type="primary"
                        size="small"
                        onClick={this.save}
                        style={{ marginRight: '15px' }}
                      >
                        保存片段
                      </Button>
                    )}
                  </span>
                }
              >
                <Tab.TabPane key="tab-jsx" tab="JSX">
                  <MonacoEditor key="jsx" code={jsx} type="jsx" />
                </Tab.TabPane>

                <Tab.TabPane key="tab-scss" tab="SCSS">
                  <MonacoEditor key="scss" code={scss} type="scss" />
                </Tab.TabPane>
              </Tab>
            )}
          </Col>
          <Col
            xxs={24}
            s={12}
            l={12}
            style={{ minWidth: '100px', paddingLeft: '25px' }}
          >
            <div
              style={{
                display: 'flex',
                flexDirection: 'row',
                alignItems: 'center',
                borderBottom: '1px dashed #ddd',
                paddingBottom: '15px',
                fontSize: '12px',
                justifyContent: 'space-between',
              }}
            >
              <span />
              <div
                style={{
                  display: 'flex',
                  flexDirection: 'row',
                  alignItems: 'center',
                }}
              >
                <Balloon
                  trigger={
                    <Icon
                      style={{ marginRight: '2px' }}
                      size="xs"
                      type="help"
                    />
                  }
                >
                  <span style={{ fontWeight: 'bold' }}>基本模式 (推荐)</span>
                  <p>
                    直接使用 eval
                    执行代码，请注意不要污染全局变量，否则可能造成污染。
                  </p>

                  <span style={{ fontWeight: 'bold' }}>隔离模式</span>
                  <p>
                    隔离模式的整个预览层由一个 iframe
                    包裹，不会受到外部环境污染，但是会带来一些副作用，如默认协议头为
                    'file:'，无法运行 serviceWroker 等。
                  </p>
                </Balloon>
                预览模式
                <Select
                  style={{ marginLeft: '10px' }}
                  size="small"
                  value={previewMode}
                  placeholder="切换预览模式"
                  onChange={this.changePreviewMode}
                >
                  <Select.Option value="context">基本模式</Select.Option>
                  <Select.Option value="iframe">隔离模式</Select.Option>
                </Select>
              </div>
            </div>

            <div style={{ paddingTop: '20px', height: '100%' }}>
              <PlaygroundPreview
                dataSource={{
                  jsx,
                  scss,
                }}
                mode={previewMode}
              />
            </div>
          </Col>
        </Row>
      </IceContainer>
    );
  }
}
