import React, { CSSProperties } from 'react';
import keycode from 'keycode'
import { ClassNamesFn, themeable } from '../../theme';
import Button from '../Button';
import Icon from '../icons';
import { RecordComponentMap } from './record-item'
import { RecordTypeEnum, ActionEnum } from './enum'
import type { NavType, DataItemType, HandleDataType, CommentType, DataComponentItemType, CommentTypeMap, ActionType } from './type'


export interface RecordProps {
  className?: string;
  classPrefix: string;
  classnames: ClassNamesFn;

  nav: Array<NavType>
  data: Array<DataItemType>
  footStyle?: CSSProperties;
  height?: string | number;// 组件高度 默认不传是取父级高度
  showHead?: boolean;// 是否显示头部
  title: string;// 头部标题
  isSort: boolean;// 是否开启排序
  refFn: Function
  onAction: (obj: ActionType) => any
}

interface RecordState {
  active: RecordTypeEnum// 选中的tab 
  entering: boolean// 输入中
  sendId: string | null// 发送id （可能是回复id、 可能是编辑id）
  sendType: ActionEnum// 发送类型
  commentInputVal: string// 评论输入框内容
  commentInputPlaceholder: string// 评论输入框提示
}



interface RecordTabProps{
  classnames: ClassNamesFn;
  tabs: NavType[]
  active: RecordTypeEnum
  onChange: Function
}

const RecordTab = (props: RecordTabProps) => {
  let { classnames: cx, tabs, active, onChange } = props;
  if(!tabs.length) return null

  return (
    <div className={cx(`Record-main-tabs`)}>
      <div className={cx(`Record-main-tabs-container`)}>
      {
        tabs.map(v=>{
          return <div className={cx(`Record-tabs-item`, {
            "Record-tabs-item__active": v.type === active
          })} key={v.type} onClick={() => onChange(v.type)}>
            <span className={cx(`Record-tabs-item-label`)}>{v.name}</span>
          </div>
        })
      }
      </div>
    </div>
  )
}

const PLACEHOLDER = 'Shift + Enter 可以换行'

class Record extends React.Component<RecordProps, RecordState>{
  messageContentRef: any
  openKeyDownMonitor: boolean

  static defaultProps = {
    nav: [],
    showHead: true,
    title: '记录',
    isSort: true,
    refFn: () => {},
  };

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

    this.state = {
      active: props.nav.length > 1? RecordTypeEnum.all: props.nav?.[0]?.type,
      entering: false,
      sendId: null,
      sendType: ActionEnum.comment,
      commentInputVal: '',
      commentInputPlaceholder: PLACEHOLDER,
    }

    this.messageContentRef = React.createRef()
    this.openKeyDownMonitor = false;

    props.refFn(this)

    document.body.addEventListener('keyup', this.handleKeyDown)

  }

  componentWillUnmount(){
    document.body.removeEventListener('keyup', this.handleKeyDown)
  }

  static getDerivedStateFromProps(nextProps: RecordProps, prevState: RecordProps){
    return null
  }

  handleKeyDown = (e: any) => {
    if(keycode(e) === 'enter' && !e.shiftKey && this.openKeyDownMonitor){
      this.sendComment();
    }
  }

  getCommentMap = (data: DataItemType[]): CommentTypeMap => {
    let commentMap: CommentTypeMap = {}
    data.forEach((v: CommentType)=>{
      if(v.type === RecordTypeEnum.comment){
        commentMap[v.id] = v;
      }
    })
    return commentMap
  }

  handleData = (): HandleDataType => {
    let {
      data,
      nav,
    } = this.props;
    let { active } = this.state; 

    let newNav: NavType[] = []
    let newData: DataComponentItemType[] = []

    if(nav.length > 1){
      newNav = [{
        name: '全部',
        type: RecordTypeEnum.all
      }, ...nav]
    }

    let commentMap = this.getCommentMap(data);

    newData = data.map((v: CommentType): DataComponentItemType =>{
      if(v.type === RecordTypeEnum.comment){
        if(v.deleted){
          return {
            ...v,
            content: '该评论已删除',
            replyId: '',// 如果改评论已被删除 就不用显示reply
          }
        }else{
          if(v.replyId in commentMap ){
            let reply = commentMap[v.replyId] || {}
            let replyDeleted = reply.deleted;
            return {
              ...v,
              reply: reply.username,
              replyContent: replyDeleted? '该评论已删除': (reply.content || ''),
              replyDeleted
            }
          }
        }
      }
      return v;
    })

    if( active !== RecordTypeEnum.all){
      newData = newData.filter((v: DataItemType)=> v.type === active)
    }
    
    return {
      data: newData,
      nav: newNav
    }
  }

  handleScrollToBottom(type?: RecordTypeEnum){
    let { active } = this.state;
    this.messageContentRef.current && (active === type || active === RecordTypeEnum.all) && (
      this.messageContentRef.current.scrollTop = this.messageContentRef.current.scrollHeight
    )
  }

  handleReset(){
    this.setState({
      entering: false,
    })
  }

  changeActive = (type: RecordTypeEnum) => {
    this.setState({
      active: type
    }, () =>{
      this.handleScrollToBottom(type)
    })
  }

  deleteComment(id: string){
    this.props.onAction({
      type: ActionEnum.del,
      id
    })
  }

  sendComment = () => {
    const {
      sendId,
      sendType,
      commentInputVal,
    } = this.state

    if(commentInputVal){
      this.props.onAction({
        type: sendType,
        id: sendId,
        content: commentInputVal
      })
      this.openKeyDownMonitor = false
    }

  }

  onEvent = (type: RecordTypeEnum, id: string, action: ActionEnum) => {
    let { data } = this.props;

    if(type === RecordTypeEnum.comment){
      let commentMap = this.getCommentMap(data);
      
      switch(action){
        case ActionEnum.del:
          this.deleteComment(id)
          break;
        case ActionEnum.edit:
          this.setState({
            entering: true,
            sendId: id,
            sendType: action,
            commentInputVal: commentMap[id]?.content || '',
            commentInputPlaceholder: PLACEHOLDER,
          })

          break;
        case ActionEnum.reply:
          this.setState({
            entering: true,
            sendId: id,
            sendType: action,
            commentInputVal: '',
            commentInputPlaceholder: `回复${commentMap[id]?.username || ''}:`,
          })
          break;
      }
    }

  }

  renderHead(){
    const {
      title,
      isSort,
      classnames: cx,
    } = this.props

    return (
      <div className={cx(`Record-header`)}>
        <div className={cx(`Record-header-title`)}>{title}</div>
        {/* {
          isSort ? (
            <div className={cx(`Record-header-sort`)} onClick={this.datasrot}>
              <span style={!this.state.sort ?{color:'#1890ff'}:{}}>
                <Icon icon='sort-asc' className='icon'></Icon>
              </span>
              <span style={this.state.sort ?{color:'#1890ff'}:{}}>
                <Icon icon='sort-desc' className='icon'></Icon>
              </span>
            </div>
          ): null
        } */}
      </div>
    )
  }

  renderContent() {
    let {
      classnames: cx,
    } = this.props;
    let { active } = this.state;

    let { data, nav } = this.handleData()
      
    
    return (
      <div className={cx(`Record-main`)}>
        
        <RecordTab classnames={cx} tabs={nav} active={active} onChange={this.changeActive}/>

        <div className={cx(`Record-main-content`)} ref={this.messageContentRef}>
          {
            data.length? (
              data.map((v: DataComponentItemType, i)=>{
                let Component: React.FC = RecordComponentMap.get(v.type)!
                if(Component){
                  // @ts-ignore
                  return <Component classnames={cx} key={i} {...v} onEvent={this.onEvent}/>
                }else {
                  return null
                }
              })
            ): (
              <div className={cx(`Record-nodata`)}>暂无数据</div>
            )
          }
        </div>
      </div>
    )
  }

  renderFootReply(){
    const { classnames: cx, data } = this.props
    const {
      entering,
      sendId,
      sendType,
    } = this.state
    
    if( entering && sendType === ActionEnum.reply ){
      let commentMap = this.getCommentMap(data);
      let reply = commentMap[sendId!]

      return (
        <div className={cx(`Record-foot-reply`)}>
          <div>
            <span>{reply.username || ''}: </span><span>{reply.content || ''}</span>
          </div>
          <div onClick={() => {
            this.setState({ sendId: null, sendType: ActionEnum.comment, commentInputPlaceholder: PLACEHOLDER })
          }}>
            <Icon icon="close" className="icon"></Icon>
          </div>
        </div>
      )
    }
    return null
  }

  renderFoot() {
    const { classnames: cx, footStyle } = this.props
    const {
      entering,
      commentInputVal,
      commentInputPlaceholder
    } = this.state

    
    return (
      <div className={cx(`Record-foot`)} style={footStyle}>

        {this.renderFootReply()}

        <div className={cx(`Record-foot-entry`)}  >
          {entering ? (
            <div className={cx(`Record-foot-entry-textarea`)} >
              <textarea placeholder={commentInputPlaceholder} rows={4} autoFocus
              value={commentInputVal}
              onInput={(e: any) => {
                this.setState({
                  commentInputVal: e.target.value
                })
              }}
              onFocus={() => {
                this.openKeyDownMonitor = true
              }}
              onBlur={(e) => {
                this.openKeyDownMonitor = false
                if (!e.target.value) {
                  this.setState({ entering: false, sendId: null })
                }
              }}
              onKeyDown={(e: any) => {
                if (keycode(e) === 'enter' && !e.shiftKey) {
                  e.preventDefault();
                }
              }}
              />
              <div>
                <Button level="primary" onClick={this.sendComment}>发送</Button>
              </div>
            </div>
          ) : (
            <div className={cx(`Record-foot-entry-none`)}>
              <span onClick={() => { 
                this.setState({ entering: true, sendId: null, sendType: ActionEnum.comment, commentInputVal: '', commentInputPlaceholder: PLACEHOLDER }) 
              }}>评论</span>
            </div>
          )}
        </div>
      </div>
    )
  }
  
  render() {
    let {
      classnames: cx,
      height,
      showHead,
    } = this.props;

    let style: React.CSSProperties = {}

    height && (style.height = height)
    return (
      <div className={cx(`Record`)} style={style}>
        {showHead && this.renderHead()}
        {this.renderContent()}
        {this.renderFoot()}
      </div>
    )
  }
}

export default themeable(Record);