import axios from 'axios'
import { ref, watch, onActivated, onMounted } from 'vue'
import { getApp } from '@/app'
import { UN_REQ_NUM } from '@/constant'
import { throttle } from '@/util'

const getOperState = (attr) => {
  const operState = ref({
    state: {
      show: false,
      id: 0, 
      ...JSON.parse(JSON.stringify(attr)) 
    },
    _readyUpdate(item) {
      operState.value.state.id = item.id
      operState.value.state.show = true
  
      Object.keys(attr).forEach(key => {
        operState.value.state[key] = attr[key]
      })

      Object.keys(attr).forEach(key => {
        if (item[key] !== void 0) {
          operState.value.state[key] = item[key]
        }
      })
    },
    readyInsert() {
      operState.value.reset()
      operState.value.state.show = true
    },
    reset() {
      Object.keys(attr).forEach(key => {
        operState.value.state[key] = attr[key]
      })
      operState.value.state.show = false
      operState.value.state.id = void 0
    },
    quit() {
      operState.value.reset()
    }
  })

  return operState
}

const getSearchState = (attr) => {
  const searchState = ref({
    state: { ...JSON.parse(JSON.stringify(attr)) },
    reset() {
      Object.keys(attr).forEach(key => {
        searchState.value.state[key] = attr[key]
      })
    }
  })

  return searchState
}


const getDataListState = (isSelect) => {
  const listStateState = ref({
    state: [],
  })

  if (isSelect) {
    listStateState.value.selectRows = []
    listStateState.value.changeSelectRows = (data) => {
      listStateState.value.selectRows = data
    }
  }

  return listStateState
}

const getPagState = () => {
  const pagState = ref({
    state: {
      currPage: 1,
      size: 12,
      total: 0
    },
    sizeChange(attr) {
      pagState.value.state.size = attr
    },
    currentChange(attr) {
      pagState.value.state.currPage = attr
    }
  })

  return pagState
}

export const getParams = (ret) => {
  let params = {}
  Object.keys(ret).forEach(key => {
    if (UN_REQ_NUM !== ret[key]) {
      if (typeof ret[key] === 'string') {
        params[key] = ret[key].trim()
      } else {
        params[key] = ret[key]
      }
    }
  })
  return params
}

const referListData = async (ret, getUrl, pagAttr = {}) => {
  let params = {
    ...(ret.search ? getParams(ret.search.value.state) : {}),
    pageNum: ret.pag.value.state.currPage,
    pageSize: ret.pag.value.state.size
  }
  let paramsStr = JSON.stringify(params)
  let dateNow = Date.now()

  if (ret.dataList.cacheNow && paramsStr === ret.dataList.cacheParams && dateNow - ret.dataList.cacheNow < 1000) {
    return;
  }
  ret.dataList.cacheParams = JSON.stringify(params)
  ret.dataList.cacheNow = dateNow

  let res = await axios.post(getUrl,  params)

  let list = pagAttr['list'] ? res.data[pagAttr['list']] : res.data.list

  if (pagAttr.fixBooStatus) {
    list.forEach(item => {
      item[pagAttr.fixBooStatus] = Boolean(item[pagAttr.fixBooStatus])
    })
  }
  
  if (pagAttr.listMap) {
    list.forEach(item => {
      item.showStatus = Boolean(item.showStatus)
      for (let key of Object.keys(pagAttr.listMap)) {
        if (key in item) {
          item[pagAttr.listMap[key]] = item[key]
        }
      }
    })
  }
  
  ret.pag.value.state.total = pagAttr['totalNum'] ? res.data[pagAttr['totalNum']] : res.data.totalNum
  ret.dataList.value.state = res.data.list = list
}


export default ({operAttr, searchAttr, throttleTime,deletealert, pagAttr, isSelect = true, getUrl, updateUrl, insertUrl, delUrl } = {}) => {
  let ret = {
    dataList: getDataListState(isSelect),
    pag: getPagState()
  }
  let watchItems = [
    () => ret.pag.value.state.currPage,
    () => ret.pag.value.state.size,
  ]

  if (operAttr) {
    const oper = getOperState(operAttr)

    oper.value.readyUpdate = function(...args) {
      oper.value._readyUpdate(...args)
      oper.value.state.__oldData = ret.dataList.value.state.find(({id}) => id === oper.value.state.id)
    }

    updateUrl && (
      oper.value.update = async (data) => {
        // if (pagAttr.fixBooStatus) {
        //   pagAttr.fixBooStatus
        //   list.forEach(item => {
        //     item[] = Boolean(item[pagAttr.fixBooStatus])
        //   })
        // }
        let target = data || {...oper.value.state}
        let updateIndex = ret.dataList.value.state.findIndex(({id}) => id === target.id)
        let item = { ...ret.dataList.value.state[updateIndex] }

        if (item) {
          Object.keys(operAttr).forEach(key => {
            if (key==pagAttr.fixBooStatus) {
              item[key] = Number(target[key])
            }
            else{
              item[key] = target[key]
            }
          })
        }
        
        await axios.post(updateUrl, data || item)
        
        ret.dataList.value.state[updateIndex] = item
        oper.value.reset()
        ret.dataList.value.refer()
      }
    )

    insertUrl && (
      oper.value.insert = async (data) => {
        let target = data || oper.value.state
        let item = {}
        if (item) {
          Object.keys(operAttr).forEach(key => {
            if (key==pagAttr.fixBooStatus) {
              item[key] = Number(target[key])
            }
            else{
              item[key] = target[key]
            }
          })
        }
        

        await axios.post(insertUrl, data || item)

        ret.dataList.value.state.push(item)
        oper.value.reset()
        ret.dataList.value.refer()
      }
    )

    ret.oper = oper
  }

  if (searchAttr) {
    const search = getSearchState(searchAttr)

    search.value.submit = () => {
      ret.dataList.value.refer()
    }
    ret.search = search

    watchItems.push(search.value.state)
  }


  if (updateUrl || delUrl) {
    if (delUrl) {
      ret.dataList.value._delete = async (data) => {
        await axios.post(delUrl, {id: data.id,sceneNum:data.num})
      }
    } else {
      ret.dataList.value._delete = async (data) => {
        data.isDelete = 1
        await axios.post(updateUrl, data)
      }
    }

    ret.dataList.value.delete = async (data) => {
      if (await getApp().$confirm(deletealert || '確定要刪除此數據嗎？', '提示')) {
        await ret.dataList.value._delete(data)
        getApp().$alert('刪除成功')
        ret.dataList.value.refer()
      }
    }

    if (isSelect) {
      ret.dataList.value.deleteSelect = async () => {
        const rows = ret.dataList.value.selectRows
        if (rows.length === 0) {
          getApp().$alert('請勾選數據後再刪除數據！', '提示')
        } else if (await getApp().$confirm(`確定要刪除這${rows.length}條數據嗎？`, '提示')) {
          await Promise.all(rows.map(item => ret.dataList.value._delete(item)))
          getApp().$alert('刪除成功')
          ret.dataList.value.refer()
        }
      }
    }
  }

  ret.dataList.value.refer = throttle(
    () => {
      referListData(ret, getUrl, pagAttr)
    },
    throttleTime === 0 ? 0 : 300
  )

  // 刷新數據
  watch( watchItems, ret.dataList.value.refer )
  // 激活再刷新一次
  onActivated(() => referListData(ret, getUrl, pagAttr))
  onMounted(() => referListData(ret, getUrl, pagAttr))

  return ret
}