
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 { sign } from '@/utils/bridge'
import Waiting from '@/components/waiting/index';
import Result from '@/components/result/index';

const url = '/api'

interface OptionsItem {
  request?: {
    text?: string
  };
  result?: {
    type?: number;
    fail?: string;
    text?: string;
  }
}

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 => {
      return config
    }, error => {
      return Promise.reject(error)
    })

    this.service.interceptors.response.use(res => {
      const data = res.data
      return data
    }, error => {
      Toast('网络异常')
      loading.hideLoading()
      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 upperChain(build: any, options?: OptionsItem, fn?: any) {
    if (!build.result) {
      Toast(build.error)
      return build
    }
    // 币钱包环境
    await this.signTransition(build.result, async (sign: any) => {
      // 签名流程
      const result = typeof sign === 'string' ? JSON.parse(sign) : sign
      if (result.error) return
      console.log(result.signHash, 'signHash')
      // 发送签名，显示等待页
      console.log(options, '----~~~~~~~~~~~~options')
      const waiting = Waiting({text: options?.request?.text || undefined})
      const send = await this.sendTransaction(result.signHash)
      // store.commit('app/SET_WAIT')
      if (send.error) {
        Toast(send.error)
        return
      }
      waiting.showWait()
      let res = {} as any
      // 定时查询结果
      const timer = setInterval(async () => {
        res = await this.getTransaction(send.result)
        if (!res.error) {
          clearInterval(timer)
          waiting.hideWait()
          // 展示错误结果
          if (res.result.receipt.ty === 1) {
            const result = Result({
              type: 2,
              fail: res.result.receipt.logs[0].log
            })
            result.showResult()
            if (fn) fn(res)
          } else {
            // 展示成功内容
            const result = Result({
              type: 1,
              text: options?.result?.text
            })
            result.showResult()
            if (fn) fn(res)
          }
        }
      }, 1000)
    })
      // web 测试
      // const waiting = Waiting({})
      // waiting.showWait()
      // const sign = await this.signTransition(build.result, test.privateKey)
      // const send = await this.sendTransaction(sign.result)
      // console.log(send)
      // if (send.error) {
      //   Toast(send.error)
      //   waiting.hideWait()
      //   return
      // }
      // store.commit('app/SET_WAIT')
      // let res = {} as any
      // const timer = setInterval(async() => {
      //   res = await this.getTransaction(send.result)
      //   console.log(res, 'res-----------')
      //   if (!res.error) {
      //     clearInterval(timer)
      //     store.commit('app/HIDE_LOADING')
      //     store.commit('app/SET_RES')
      //     if (res.result.receipt.ty === 1) {
      //       store.commit('app/SET_TYPE', 2)
      //       store.commit('app/SET_FAILTEXT', res.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, options?: OptionsItem, fn?: any) {
    const build = await this.chainRequire('rankvote.CreateRankVoteTx', [data])
    await this.upperChain(build, options, fn)
  }

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

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

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

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

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

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

  /**
   * 用户转移投票项目权限
   * @param data 
   * @returns 
   */
  async memberChangeVote(data: memberChangeVote, options?: OptionsItem, fn?: any) {
    const build = await this.chainRequire('rankvote.TransferRankVoteTx', [data])
    await this.upperChain(build, options, 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
// })
