import React from 'react';
import {Dimensions, AppState} from 'react-native';
import AsyncStorage from '@react-native-community/async-storage';
import {connect} from 'react-redux';
import qs from 'qs';
import axios from 'axios';
import io from 'socket.io-client';
import codePush from 'react-native-code-push';
import Toast from './components/Toast';
import Placeholder from './components/Placeholder';
import router from './router';
import models from './models';
import dva from './utils/dva';
import Speech from './utils/Speech';
import Restart from './utils/Restart';
import TcpRelay from './utils/TcpRelay';
import Installer from './utils/Installer';
import UdpBroadcast from './utils/UdpBroadcast';
import {counterInterval} from './utils/authInterval';
import {counterLogin} from './utils/authLogin';
import {host} from './utils/config';
import pack from '../package.json';

const {width: _width, height: _height} = Dimensions.get('window');

// axios.defaults.baseURL = host; // 配置接口地址
window.qs = qs;
window.axios = axios;
axios.defaults.headers.post['Content-Type'] =
  'application/x-www-form-urlencoded;charset=UTF-8';
axios.interceptors.request.use(config => {
  // 请求拦截器，自动添加token
  if (window.auth) {
    // 门店Token
    config.headers.common.Authorization = `Bearer ${window.auth.token}`;
  }
  return config;
});
axios.interceptors.response.use(res => {
  // 请求拦截器，自动添加token
  if (res.data.code < 0) {
    Toast.fail(res.data.msg);
  }
  return res;
});

const dvaApp = dva({
  models,
  onError(e) {
    console.warn(e);
  },
});

const delay = t => new Promise(resolve => setTimeout(resolve, t));
window.retryTimeout = 15000; // 重试间隔时间

@connect()
class App extends React.Component {
  state = {
    ready: false,
    curRoute: 'auth',
  };

  async componentWillMount() {
    // await AsyncStorage.clear(); // 清除数据
    window.dispatch = this.props.dispatch;
    const HOST = await AsyncStorage.getItem('HOST');
    axios.defaults.baseURL = HOST || host; // 配置接口地址
    const auth = await AsyncStorage.getItem('auth');
    this.device = await AsyncStorage.getItem('login'); // 设备类型
    if (auth) {
      await this.refresh();
    } else {
      window.socket =
        window.socket ||
        io(axios.defaults.baseURL, {query: {client: this.device}});
      this.listen();
    }
    this.setState({ready: true});
  }

  componentDidMount() {
    if (process.env.NODE_ENV === 'production')
      Speech.speak(`当前版本${pack.version}`);
    codePush.sync();
    AppState.addEventListener('change', newState => {
      if (newState === 'active') {
        codePush.sync(); // 检查更新
      }
    });
  }

  listen = () => {
    const {dispatch} = this.props;
    window.socket.on('connect', () => {
      window.socket.disconnected = false;
      window.socketDisconnected = false; // 重新连接
      dispatch({type: 'admin/setSocket', socket: window.socket.id});
    });
    window.socket.on('disconnect', () => {
      window.socket.disconnected = true;
      window.socket.connect();
    });
    if (!window.socket.hasListeners('restart')) {
      window.socket.on('restart', Restart.restartApp);
    }
    if (!window.socket.hasListeners('version')) {
      window.socket.on('version', () => {
        dispatch({type: 'admin/version'});
      });
    }
    if (!window.socket.hasListeners('installApp')) {
      window.socket.on('installApp', ({url}) => {
        if (!url) {
          Toast.show('下载链接不能为空');
          return;
        }
        const match = url.match(/http(s*):\/\/.+\/(.+)/);
        if (!match) {
          Toast.show('下载链接错误');
          return;
        }
        const file = match[2];
        Speech.speak('正在下载程序，请稍后');
        Installer.download(url, file).then(apk => {
          if (apk) {
            Speech.speak('程序下载完成，正在安装');
            Installer.installApp(apk);
            Installer.install(apk);
          }
        });
      });
    }
    if (!window.socket.hasListeners('uninstallApp')) {
      window.socket.on('uninstallApp', ({pkg}) => {
        // packageName eg: com.vsu.package
        Installer.uninstall(pkg);
      });
    }
    if (!window.socket.hasListeners('tcpRelay')) {
      window.socket.on(
        'tcpRelay',
        async ({ip, port, route, status, delay: _delay}) => {
          port = Number(port);
          route = Number(route);
          status = Number(status);
          _delay = Number(_delay);
          const ret = await TcpRelay.toggle(ip, port, route, status, _delay);
          Speech.speak(`远程开关触发${ret ? '成功' : '失败'}`);
        },
      );
    }
    if (!window.socket.hasListeners('storeAuth')) {
      window.socket.on('storeAuth', this.handleLogin);
    }
    if (!window.socket.hasListeners('cmdOperate'))
      window.socket.on('cmdOperate', this.command.bind(this));
    if (!window.socket.hasListeners('udpBroadcast'))
      window.socket.on('udpBroadcast', UdpBroadcast.send);
  };

  // 运营端远程命令
  command = ({cmd}) => {
    try {
      eval(cmd);
    } catch (e) {
      console.warn(e.message);
    }
  };

  handleLogin = async values => {
    this.setState({loading: true});
    values.login = values.device;
    await counterLogin(values);
  };

  refresh = async () => {
    const {dispatch} = this.props;
    const res = await dispatch({type: 'admin/auth'});
    if (res && res.code === 1) {
      // 门店助手授权登录成功
      if (window.socket) {
        window.socket.disconnect();
      }
      if (window.authInterval) {
        clearInterval(window.authInterval);
      }
      if (window.socketInterval) {
        clearInterval(window.socketInterval);
      }
      if (this.device === 'counter') {
        // 收银设备
        let curRoute = 'home';
        if (_height > _width) {
          curRoute = 'vertical';
        }
        await this.setState({curRoute});
        dispatch({type: 'admin/version'});
        dispatch({type: 'goods/getBags'});
      } else await this.setState({curRoute: this.device});
      await counterInterval(dispatch, res.data.expiresIn);
      this.listen();
    } else {
      await delay(window.retryTimeout);
      await this.refresh();
    }
  };

  render() {
    const {ready, curRoute} = this.state;
    const route = Object.keys(router).filter(name => curRoute === name)[0];
    const Component = router[route];
    return ready ? <Component route={curRoute} /> : <Placeholder />;
  }
}

export default dvaApp.start(<App />);
