import axios,{AxiosInstance} from "axios";
// import axios,{AxiosInstance,AxiosResponse} from "axios";
import {CreateVoteDto, attendVote, memberInfo, delMember, memberVote, memberCloseVote, delItem, activityItem, memberChangeVote, voteDetails, voteRest, voteList, tradeList, hashList, blockInfo, listItem} from '@/types/Dto'
import { test } from '@/constants/test'
import store from '@/store/index'
import loading from '@/components/loading'
import { Toast } from "vant"
import { whiteList } from "@/constants/whiteList"
import { sign } from '@/utils/bridge'


function isSame(w: any, c: any) {
  const _d = c.data
  let o = {} as any
  if (typeof _d === 'string') {
    o = JSON.parse(_d)
  } else {
    o = _d
  }
  for (const item of w) {
    if (item.method === o.method && item.funcName === o.params[0].funcName) {
      return true
    }
  }
  return false
}

// const url = process.env.NODE_ENV === 'development' ? 'http://172.16.100.93:8901' : '/api'
const url = '/api'

interface Account{
    address: string
    privateKey:string
    publicKey?:string
}

// type Callback = (data:AxiosResponse<any>)=>any

class ChainService {
    service:AxiosInstance
    account:Account

    constructor(url:string,account:Account){
        this.account = account;
        this.service = axios.create({
            baseURL:url,
            timeout: 15000,
            method:'post'
        })
        this.service.interceptors.request.use(config => {
          // 加载页设置 (过滤等待验证接口及名称校验接口)
          if (config.data.method !== 'Chain33.QueryTransaction' && !isSame(whiteList, config)) {
            loading.showLoading()
            store.commit('app/ADD_REQUEST')
            // console.log('request:',(store as any).state.app.requestCount)
            // console.log(config.data)
          }
          return config
        }, error => {
          return Promise.reject(error)
        })
  
        this.service.interceptors.response.use(res => {
          const _d = res.config.data
          let o = {} as any
          if (typeof _d === 'string') {
            o = JSON.parse(_d)
          } else {
            o = _d
          }
          // 加载页设置
          if (o.method !== 'Chain33.QueryTransaction'  && !isSame(whiteList, res.config)) {
            store.commit('app/DEC_REQUEST')
            // console.log('res:',(store as any).state.app.requestCount)
            // console.log(res.config.data)
            if ((store as any).state.app.requestCount === 0) {
              loading.hideLoading()
            }
          }
          return res
        }, error => {
            Toast('网络异常')
            loading.hideLoading()
            // store.commit('app/SET_ERROR')
            return Promise.reject(error)
        })
    }


    /**
     * 请求区块链RPC接口的基本方法
     * @param method 区块链请求方法
     * @param data 请求的数据内容
     * @param cb 回掉方式获取Response
     * @returns 
     */
    private async chainRequire(method:string,data:any[], b?: boolean, _this?: any, cb?:any){
      const CancelToken = axios.CancelToken;
      // const source = CancelToken.source();
       return await this.service.request({
            data:{
                "jsonrpc":"2.0",
                id:1,
                method:method,
                params:data
            },
            cancelToken: b ? new CancelToken(function executor(c) {
              _this.cancelAjax = c
            }) : undefined
        }).then(res=>{
            if(cb){
            return cb(res)
            }
            return res
        }).catch((err)=>{
            if(cb){
                return cb(err)
            }
            return err
        })

    }

    private async signFunc(build: any, fn?: any, fail?: any) {
      if (!build.data.result) {
        Toast(build.data.error)
        return build
      }
      // 币钱包环境
      await this.signTransition(build.data.result, async (sign: any) => {
        console.log(sign)
        let s = {} as any
        if (typeof sign === 'string') {
          s = JSON.parse(sign)
        } else {
          s = sign
        }
        if (s.error) return
        console.log(s.signHash)
        const send = await this.sendTransaction(s.signHash)
        store.commit('app/SET_WAIT')
        let res = {} as any
        const timer = setInterval(async() => {
          res = await this.getTransaction(send.data.result)
          if (!res.data.error) {
            clearInterval(timer)
            store.commit('app/HIDE_LOADING')
            store.commit('app/SET_RES')
            if (res.data.result.receipt.ty === 1) {
              store.commit('app/SET_TYPE', 2)
              store.commit('app/SET_RESULT', res.data.result.receipt.logs[0].log)
              if (fail) fail()
            } else {
              store.commit('app/SET_TYPE', 1)
              if (fn) fn(res)
            }
          }
        }, 1000)
      })
    //   // web 测试
    //   const sign = await this.signTransition(build.data.result, test.privateKey)
    //   const send = await this.sendTransaction(sign.data.result)
    //   store.commit('app/SET_WAIT')
    //   let res = {} as any
    //   const timer = setInterval(async() => {
    //     res = await this.getTransaction(send.data.result)
    //     if (!res.data.error) {
    //       clearInterval(timer)
    //       store.commit('app/HIDE_LOADING')
    //       store.commit('app/SET_RES')
    //       if (res.data.result.receipt.ty === 1) {
    //         store.commit('app/SET_TYPE', 2)
    //         store.commit('app/SET_RESULT', res.data.result.receipt.logs[0].log)
    //         if (fail) fail()
    //       } else {
    //         store.commit('app/SET_TYPE', 1)
    //         if (fn) fn(res)
    //       }
    //     }
    //   }, 1000)
    }

    /**
     * 创建投票项目
     * @param data
     * @returns 
     */
    async createVote(data:CreateVoteDto, fn?: any){
      const build = await this.chainRequire('rankvote.CreateRankVoteTx',[data])
      await this.signFunc(build, fn)
    }

    /**
     * 报名活动社区投票提案
     * @param data 
     * @returns 
     */
    async attendVote(data: attendVote, fn?: any) {
      const build = await this.chainRequire('rankvote.SignUpRankVoteTx', [data])
      await this.signFunc(build, fn)
    }

    /**
     * 添加成员
     * @param data 
     * @returns 
     */
    async addMember(data: memberInfo, fn?: any) {
      const build = await this.chainRequire('rankvote.AddRankVoteMemberTx', [data])
      await this.signFunc(build, fn)
    }

    /**
     * 删除用户
     * @param data 
     * @param fn 
     */
    async delMember(data: delMember, fn?: any) {
      const build = await this.chainRequire('rankvote.DelRankVoteMemberTx', [data])
      await this.signFunc(build, fn)
    }

    /**
     * 用户投票
     * @param data 
     * @returns 
     */
    async memberVote(data: memberVote, fn?: any) {
      const build =  await this.chainRequire('rankvote.CommitRankVoteTx', [data])
      await this.signFunc(build, fn)
    }

    /**
     * 用户关闭投票
     * @param data 
     * @returns 
     */
    async memberCloseVote(data: memberCloseVote, fn?: any) {
      const build = await this.chainRequire('rankvote.CloseRankVoteTx', [data])
      await this.signFunc(build, fn)
    }

    /**
     * 关闭投票选项
     * @param data 
     * @param fn 
     */
    async delOption(data: delItem, fn?: any) {
      const build = await this.chainRequire('rankvote.DelRankVoteOptTx', [data])
      await this.signFunc(build, fn)
    }

    /**
     * 用户转移投票项目权限
     * @param data 
     * @returns 
     */
    async memberChangeVote(data: memberChangeVote, fn?: any) {
      const build = await this.chainRequire('rankvote.TransferRankVoteTx', [data])
      await this.signFunc(build, fn)
    }

    /**
     * 投票名称是否占用
     * @param data 
     * @returns 
     */
    async checkName(data: string) {
      return await this.chainRequire('Chain33.Query', [{
        execer: 'user.p.szhtest.rankvote',
        funcName: 'GetVoteByName',
        payload: {
          data: data
        }
      }])
    }

    /**
     * 获取投票活动详情
     * @param data 
     * @param b 是否开启 cancelToken
     * @param t cancelToken 回调 this
     * @returns 
     */
    async voteDetails(data: voteDetails, b?: boolean, t?: any) {
      const res = await this.chainRequire('Chain33.Query', [data], b, t)
      return res
    }

    /**
     * 获取地址投票余额资产
     * @param data 
     * @returns 
     */
    async voteRest(data: voteRest) {
      const res = await this.chainRequire('Chain33.Query', [data])
      return res
    }

    /**
     * 获得投票项目列表
     * @param data 
     * @returns 
     */
    async voteList(data: voteList) {
      const res = await this.chainRequire('Chain33.Query', [data])
      return res
    }

    /**
     * 获取投票交易列表
     * @param data 
     * @returns 
     */
    async tradeList(data: tradeList) {
      const res = await this.chainRequire('Chain33.Query', [data])
      return res
    }

    /**
     * 获取投票hash交易列表
     * @param data 
     * @returns 
     */
    async hashList(data: hashList) {
      const res = await this.chainRequire('Chain33.Query', [data])
      return res
    }

    /**
     * 获取主链平行链节点高度
     * @returns 
     */
    async getHeight() {
      const res = await this.chainRequire('Chain33.Query', [{
        execer: 'user.p.szhtest.rankvote',
        funcName: 'GetMainHeight',
        payload: {}
      }])
      return res
    }

    /**
     * 我参与的项目
     * @param data 
     * @returns 
     */
    async getMyList(data: listItem) {
      return await this.chainRequire('Chain33.Query', [data])
    }

    /**
     * 我参与的社区选项
     * @param data 
     * @returns 
     */
    async getMyOption(data: activityItem) {
      return await this.chainRequire('Chain33.Query', [data])
    }

    /**
     * 我发起的社区选项
     * @param data 
     * @returns 
     */
    async getMySetOption(data: activityItem) {
      return await this.chainRequire('Chain33.Query', [data])
    }

    /**
     * 获取块信息
     * @param data 
     * @returns 
     */
    async getBlocks(data: blockInfo) {
      return await this.chainRequire('Chain33.GetBlocks', [data])
    }

    /**
     * 获取最新区块
     * @returns 
     */
    async getLastBlocks() {
      return await this.chainRequire('Chain33.GetLastHeader', [])
    }

    /**
     * 发送签名
     * @param txHex 
     * @returns 
     */
    private async sendTransaction(txHex:string){
      return await this.chainRequire('Chain33.SendTransaction',[{
          data: txHex
      }])
    }

    /**
     * 获取签名
     * @param txHex 
     * @param privateKey 
     * @returns 
     */
    // private async signTransition(txHex:string,privateKey?:string){
    //   return await this.chainRequire('Chain33.SignRawTx',[{
    //       privkey: privateKey,
    //       txHex: txHex,
    //       expire: '1h',
    //   }])
    // }

    private async signTransition(txHex: string, fn?: any){
      sign({
        createHash: txHex,
        exer: 'user.p.szhtest.rankvote',
        isWithhold: 1
      }, fn)
    }

    /**
     * 获取提交结果
     * @param hash 
     * @returns 
     */
    private async getTransaction(hash: string) {
      return await this.chainRequire('Chain33.QueryTransaction', [{
        hash: hash
      }])
    }
}

export const service = new ChainService(url, {
  address: test.addr,
  privateKey: test.privateKey
})

// 33chain
// export const chainService = new ChainService('http://172.16.100.75:8801', {
//   address: test.addr,
//   privateKey: test.privateKey
// })
