import React, { Component } from "react";
import PropTypes from "prop-types";
import { message } from "antd";
import axios from "axios";
import Cookies from "js-cookie";
import intl from "react-intl-universal";
import { ERROR_DEFAULT, LIMIT, COMMENT_TYPE, LANGUAGE_LINK } from "./constant";
import { CommentContext } from "./Comment";
import { isFunction } from "./helper";
import CommentInput from "./components/CommentInput";
import CommentList from "./components/CommentList";
import Editor from "./components/Editor";
import RenderText from "./components/RenderText";
import { SUPPORT_LOCALES, LOCALES_RESPONSE } from "./lang";
import "./App.css";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      loading: {},

      // oss 配置
      oss: {},

      // 评论数据
      list: [],
      page: 1,
      total: 0,
      // 是否没有更多评论了
      isNoMoreComment: false,
      initDone: false,
      locale: "zh-CN"
    };
    this.handleChangeLoading = this.handleChangeLoading.bind(this);
    this.sCreateComment = this.sCreateComment.bind(this);
    this.sDeleteComment = this.sDeleteComment.bind(this);
    this.sCommentFavor = this.sCommentFavor.bind(this);
    this.sCreateReply = this.sCreateReply.bind(this);
    this.sDeleteReply = this.sDeleteReply.bind(this);
    this.errorHandler = this.errorHandler.bind(this);
    this.sGetComment = this.sGetComment.bind(this);
    this.sReplyFavor = this.sReplyFavor.bind(this);
    this.sGetReply = this.sGetReply.bind(this);
    this.sOssSts = this.sOssSts.bind(this);
  }

  componentWillMount() {
    this.axios = axios;
    this.axios.defaults.withCredentials = true;
    if (this.props.token) {
      this.axios.defaults.headers.common["Authorization"] = `Bearer ${
        this.props.token
      }`;
    }
  }

  componentDidMount() {
    this.loadLocales();
  }

  /**
   * 加载语言包
   * 只能根据url或者传入的props来确定加载哪个语言包
   * 优先级：传入的props > url
   */
  loadLocales() {
    let { locales: currentLocale } = this.props;
    const cookieLang = Cookies.get("lnk_lang");
    if (!currentLocale) {
      currentLocale =
        cookieLang ||
        intl.determineLocale({
          urlLocaleKey: "lang"
        });
    }
    currentLocale = SUPPORT_LOCALES.find(item => item.value === currentLocale)
      ? currentLocale
      : "zh-CN";
    const version = require("./version.json").hash;
    // 使用绝对路径
    const languageURL = `${LANGUAGE_LINK}/${currentLocale}.json?v=${version}`;
    return fetch(languageURL)
      .then(response => {
        if (response.status >= 400) {
          throw new Error("Bad response from server");
        }
        return response.json();
      })
      .then(data => {
        // console.log('data: ', data);
        intl
          .init({
            currentLocale,
            locales: {
              [currentLocale]: data
            }
          })
          .then(() => {
            this.setState({ initDone: true, locale: currentLocale });
          });
      });
  }

  error(msg, info = {}) {
    if (this.props.showError) {
      message.error(msg);
    }
    if (this.props.onError) {
      this.props.onError(msg, info);
    }
  }

  errorHandler(error) {
    const { locale } = this.state;
    const localResponse = LOCALES_RESPONSE[locale];
    if (error.response && error.response.data && error.response.data.msg) {
      this.error(localResponse[error.response.data.msg] || ERROR_DEFAULT, {
        response: error.response
      });
      return;
    }
    this.error(localResponse[error.response.data.msg] || ERROR_DEFAULT, {
      response: error.response
    });
  }

  /**
   * 改变 loading 状态
   * @param {string} key key
   * @param {string} value value
   */
  handleChangeLoading(key, value) {
    const { loading } = this.state;
    loading[key] = value;
    this.setState({ loading });
  }

  /**
   * 获取评论列表
   */
  sGetComment({ page = 1 } = {}) {
    const { pageType } = this.props;
    this.handleChangeLoading("sGetComment", true);
    const { API, type, businessId, limit } = this.props;
    this.axios
      .get(
        `${API}/comments?type=${type}&business_id=${businessId}&page=${page}&limit=${limit}`
      )
      .then(response => {
        const { list, page, total } = response.data;
        if (list) {
          let newList = list;
          let { list: oldList } = this.state;
          if (pageType === "more") {
            if (page > 1) {
              // 删除临时数据
              oldList = oldList.filter(o => !o.isTemporary);
              newList = oldList.concat(newList);
            }
          } else if (pageType === "pagination") {
            // TODO 滚动到顶部
            window.scrollTo(0, 0);
          }

          this.setState({
            list: newList,
            page,
            total
          });
          this.props.onCountChange(total);
        } else {
          message.info(intl.get("message.noMoreComment"));
          this.setState({
            isNoMoreComment: true
          });
        }
      })
      .catch(this.errorHandler)
      .finally(() => {
        this.handleChangeLoading("sGetComment", false);
      });
  }

  /**
   * 获取更多回复
   */
  sGetReply({ commentId, page = 1 } = {}) {
    this.handleChangeLoading("sGetReply", true);
    const { API, limit } = this.props;
    this.axios
      .get(`${API}/replies?comment_id=${commentId}&page=${page}&limit=${limit}`)
      .then(response => {
        if (!response.data.list) {
          message.info(intl.get("message.noMoreData"));
        }
        const list = this.state.list.map(item => {
          if (item.id === commentId) {
            if (!item.replies) item.replies = [];
            if (response.data.list) {
              if (page === 1) {
                // 如果当前页数为第一页，则清空当前所有的 replies
                // 并将获取到的 replies 存放在 state
                item.replies = response.data.list;
              } else {
                item.replies = item.replies
                  .filter(o => !o.isTemporary)
                  .concat(response.data.list);
                // 如果当前页数非第一页，则合并 replies
              }
              item.reply_count = response.data.total;
              item.reply_page = response.data.page;
            } else {
              item.isNoMoreReply = true;
            }
          }
          return item;
        });
        this.setState({ list });
      })
      .catch(this.errorHandler)
      .finally(() => {
        this.handleChangeLoading("sGetReply", false);
      });
  }

  /**
   * 添加评论
   * @param {object} {content} comment content
   */
  sCreateComment({ content } = {}, cb) {
    if (!content) return this.error(intl.get("message.notNull"));
    this.handleChangeLoading("sCreateComment", true);
    const { API, type, businessId, businessUserId } = this.props;
    this.axios(`${API}/comments`, {
      method: "post",
      data: {
        type,
        business_id: businessId,
        business_user_id: businessUserId,
        content
      },
      withCredentials: true
    })
      .then(response => {
        if (this.props.showAlertComment) {
          message.success(intl.get("message.success"));
        }
        if (isFunction(cb)) cb(response.data);
        // 将数据写入到 list 中
        // 临时插入
        // 等到获取数据之后，删除临时数据
        const { list, total } = this.state;
        list.unshift({
          ...response.data,
          isTemporary: true // 临时的数据
        });
        this.setState({ list, total: total + 1 });
        this.props.onCountChange(total + 1);
      })
      .catch(this.errorHandler)
      .finally(() => {
        this.handleChangeLoading("sCreateComment", false);
      });
  }

  /**
   * 删除评论
   */
  sDeleteComment(commentId) {
    this.handleChangeLoading("sDeleteComment", true);
    const { API } = this.props;
    this.axios(`${API}/comments/${commentId}`, {
      method: "delete",
      withCredentials: true
    })
      .then(() => {
        const { list, total } = this.state;
        const res = list.filter(item => item.id !== commentId);
        const deletedItem = list.find(item => item.id === commentId);
        this.setState({ list: res, total: total - 1 });
        this.props.onDelete(COMMENT_TYPE.COMMENT, deletedItem);
        this.props.onCountChange(total - 1);
      })
      .catch(this.errorHandler)
      .finally(() => {
        this.handleChangeLoading("sDeleteComment", false);
      });
  }

  /**
   * 添加回复
   * 回复评论/回复回复
   * @param {object} data { comment_id, content, [reply_id] }
   */
  sCreateReply(data, cb) {
    if (!data.content) return this.error(intl.get("message.replyNoNull"));
    this.handleChangeLoading("sCreateReply", true);
    const { API } = this.props;
    this.axios(`${API}/replies`, {
      method: "post",
      data,
      withCredentials: true
    })
      .then(response => {
        if (this.props.showAlertReply) {
          message.success(intl.get("message.replySuccess"));
        }
        if (isFunction(cb)) cb(response.data);
        // 将数据写入到 list 中
        // 临时插入
        // 等到获取数据之后，删除临时数据
        const list = this.state.list.map(item => {
          if (item.id === data.comment_id) {
            if (!item.replies) item.replies = [];
            item.replies.push({
              ...response.data,
              isTemporary: true // 临时的数据
            });
            item.reply_count += 1;
          }
          return item;
        });
        this.setState({ list });
      })
      .catch(this.errorHandler)
      .finally(() => {
        this.handleChangeLoading("sCreateReply", false);
      });
  }

  /**
   * 删除回复
   * @param {*} replyId
   * @param {*} commentId
   */
  sDeleteReply(replyId, commentId) {
    this.handleChangeLoading("sDeleteReply", true);
    const { API } = this.props;
    this.axios(`${API}/replies/${replyId}?CommentID=${commentId}`, {
      method: "delete",
      withCredentials: true
    })
      .then(() => {
        let deletedItem = null;
        const list = this.state.list.map(item => {
          if (item.id === commentId) {
            const replies = item.replies.filter(item => item.id !== replyId);
            deletedItem = item.replies.find(item => item.id === replyId);
            item.replies = replies;
            item.reply_count -= 1;
          }
          return item;
        });
        this.setState({ list });
        this.props.onDelete(COMMENT_TYPE.REPLY, deletedItem);
      })
      .catch(this.errorHandler)
      .finally(() => {
        this.handleChangeLoading("sDeleteReply", false);
      });
  }

  /**
   * 评论 点赞/取消点赞
   * @param {string} commentId { commentId }
   * @param {boolean} favored   是否已经点过赞
   */
  sCommentFavor(commentId, favored) {
    this.handleChangeLoading("sCommentFavor", true);
    const { API } = this.props;
    this.axios(`${API}/comments/${commentId}/favor`, {
      method: favored ? "delete" : "put",
      withCredentials: true
    })
      .then(response => {
        if (this.props.showAlertFavor) {
          message.success(
            favored
              ? intl.get("message.cancelLickSuccess")
              : intl.get("message.likeSuccess")
          );
        }
        // 更新 list 中的该项数据的 favored
        const list = this.state.list.map(item => {
          if (item.id === commentId) {
            item.favored = !favored;
            item.favor_count += favored ? -1 : 1;
          }
          return item;
        });
        this.setState({ list });
      })
      .catch(this.errorHandler)
      .finally(() => {
        this.handleChangeLoading("sCommentFavor", false);
      });
  }

  /**
   * 回复 点赞/取消点赞
   * @param {string} replyId  replyId
   * @param {string} commentId  commentId
   * @param {boolean} favored   是否已经点过赞
   */
  sReplyFavor(replyId, commentId, favored) {
    this.handleChangeLoading("sReplyFavor", true);
    const { API } = this.props;
    this.axios(`${API}/replies/${replyId}/favor`, {
      method: favored ? "delete" : "put",
      data: {
        comment_id: commentId
      },
      withCredentials: true
    })
      .then(response => {
        message.success(
          favored
            ? intl.get("message.cancelLickSuccess")
            : intl.get("message.likeSuccess")
        );
        // 更新 list 中的该项数据的 favored
        const list = this.state.list.map(item => {
          if (item.id === commentId) {
            item.replies = item.replies.map(r => {
              if (r.id === replyId) {
                r.favored = !favored;
                // r.favor_count =  response.data.favor_count;
                // 点赞数 +1，而不是使用后端返回的点赞数
                // 不然如果返回的不是增加 1，用户可能以为程序错误
                r.favor_count += favored ? -1 : 1;
              }
              return r;
            });
          }
          return item;
        });
        this.setState({ list });
      })
      .catch(this.errorHandler)
      .finally(() => {
        this.handleChangeLoading("sReplyFavor", false);
      });
  }

  /**
   * 获取 OSS 上传的参数
   */
  sOssSts() {
    this.handleChangeLoading("sOssSts", true);
    const { API } = this.props;
    this.axios
      .get(`${API}/oss/sts`)
      .then(response => {
        this.setState({ oss: { ...response.data } });
      })
      .catch(this.errorHandler)
      .finally(() => {
        this.handleChangeLoading("sOssSts", false);
      });
  }

  render() {
    // 添加到 Context 的数据
    const value = {
      ...this.state,
      ...this.props,
      sCreateComment: this.sCreateComment,
      sGetComment: this.sGetComment,
      sCommentFavor: this.sCommentFavor,
      sReplyFavor: this.sReplyFavor,
      sCreateReply: this.sCreateReply,
      sGetReply: this.sGetReply,
      sOssSts: this.sOssSts,
      sDeleteComment: this.sDeleteComment,
      sDeleteReply: this.sDeleteReply
    };

    return (
      this.state.initDone && (
        <CommentContext.Provider value={value}>
          <div className="comment">
            {this.props.showEditor && (
              <CommentInput content={this.props.children} />
            )}
            {this.props.showList && (
              <div style={{ marginTop: 20 }}>
                <CommentList />
              </div>
            )}
          </div>
        </CommentContext.Provider>
      )
    );
  }
}

App.propTypes = {
  type: PropTypes.number.isRequired, // 评论的 type
  businessId: PropTypes.string.isRequired, // 评论的 business_id
  businessUserId: PropTypes.number,
  API: PropTypes.string, // 评论的 API 前缀
  showList: PropTypes.bool, // 是否显示评论列表
  showEditor: PropTypes.bool, // 是否显示评论输入框
  showAlertComment: PropTypes.bool, // 评论成功之后，是否通过 Antd 的 Message 组件进行提示
  showAlertReply: PropTypes.bool, // 回复成功之后，是否通过 Antd 的 Message 组件进行提示
  showAlertFavor: PropTypes.bool, // 点赞/取消点赞成功之后，是否通过 Antd 的 Message 组件进行提示
  showError: PropTypes.bool, // 是否使用Antd的Message组件提示错误信息
  onError: PropTypes.func, // 错误回调, 出错了会被调用
  userId: PropTypes.number, // 用户id, comment内部不维护用户id, 调用组件时传递过来, 目前用于判断是否显示删除按钮
  pageType: PropTypes.string, // 分页类型
  page: PropTypes.number, // 页码
  limit: PropTypes.number, // 一次加载评论数量
  onPageChange: PropTypes.func, // 页码变化回调
  onGetMoreBtnClick: PropTypes.func, // 点击查看更多按钮回调
  onDelete: PropTypes.func,
  locales: PropTypes.string, //  传入的语言环境， en-US/zh-CN
  onCountChange: PropTypes.func // 评论数量变更时的回调
};

App.defaultProps = {
  businessUserId: 0,
  API: "//api.links123.net/comment/v1",
  showList: true,
  showEditor: true,
  showAlertComment: false,
  showAlertReply: false,
  showAlertFavor: false,
  showError: true,
  pageType: "more",
  limit: LIMIT,
  onGetMoreBtnClick: () => {},
  onPageChange: page => {},
  onDelete: () => {},
  onCountChange: () => {}
};

export { Editor, RenderText };

export default App;
