import { h, render, Component } from 'preact'; // eslint-disable-line no-unused-vars
// content and config:
import content from '../content/module.json';
import config from '../config';
// services and helper:
import api from '../utilities/api';
import { fixedDigits } from '../utilities/formatter';
// screens and items:
import TitleScreen from './TitleScreen.jsx';
import FinalScreen from './FinalScreen.jsx';
import QuestionScreen from './QuestionScreen.jsx';

/**
 * titlescreen, questionscreen (repeat), finalscreen
 */
export default class App extends Component {

  // construct and initialize functions
  constructor (props) {
    super(props);

    // for example: (1400 - 200) / 3 -> 400 points per section
    const diff = (config.numberOfPoints.first - config.numberOfPoints.last) / 3;

    // for example: 1400, 1000, 600, 200
    this.numberOfPoints = [
      parseInt(config.numberOfPoints.first, 10),
      parseInt(config.numberOfPoints.first - diff, 10),
      parseInt(config.numberOfPoints.last + diff, 10),
      parseInt(config.numberOfPoints.last, 10)
    ];

    this.state = {
      route: 'titlescreen',                          // current screen
      isFetching: false,                             // currently performing XHR?
      userId: null,                                  // current user id for posting
      token: null,                                   // current access token
      mode: 'intro',                                 // current mode: init || intro || question || score
      currentQuestion: 0,                            // current question number
      currentAnswerIndex: null,                      // index in question pair of the currently set answer
      currentAnswerCorrect: false,                   // is the currently set question the correct one?
      currentNumberOfPoints: this.numberOfPoints[0], // current number of points
      nextNumberOfPoints: this.numberOfPoints[1],    // next number of points
      currentAmount: config.highlightedAmount,       // curent amount of points to be highlighted
      voteRatios: null                               // get votes from other users
    };

    if (window.location.hash) this.state.route = window.location.hash.replace('#', '');

    // context binding
    this.navigate = this.navigate.bind(this);
    this.toNextQuestion = this.toNextQuestion.bind(this);
    this.setAnswer = this.setAnswer.bind(this);
    this.getUserVotes = this.getUserVotes.bind(this);
    this.reset = this.reset.bind(this);
    this.setup = this.setup.bind(this);
    this.endUserSession = this.endUserSession.bind(this);
  }

  // to next question
  toNextQuestion () {
    // intro screen, introduce bubbles :P
    if (this.state.mode === 'intro') {
      this.setState({
        // currentQuestion: null,
        mode: 'init',
        route: 'question'
      });
    } else if (this.state.currentQuestion === 0 && this.state.mode === 'init') {
      // is first question?
      this.setState({
        currentAmount: 0,
        mode: 'question',
        route: 'question'
      });
    } else if (this.state.currentQuestion === 3 && this.state.mode === 'score') {
      // is last question? go to final screen
      this.setState({
        route: 'finalscreen',
        mode: 'intro',
        currentNumberOfPoints: this.numberOfPoints[0],
        currentAmount: config.highlightedAmount,
        currentQuestion: 0,
        currentAnswerIndex: null,
        currentAnswerCorrect: false,
        nextNumberOfPoints: this.numberOfPoints[1],
        voteRatios: null
      });
    } else if (this.state.voteRatios && this.state.mode === 'question') {
      // go to score screen
      this.setState({
        route: 'question',
        mode: 'score'
      });
    } else {
      // go to next question
      this.setState({
        route: 'question',
        mode: 'question',
        currentQuestion: this.state.currentQuestion + 1,
        currentAnswerIndex: null,
        currentNumberOfPoints: this.numberOfPoints[this.state.currentQuestion + 1],
        nextNumberOfPoints: this.numberOfPoints[this.state.currentQuestion + 2],
        currentAmount: 0,
        voteRatios: null
      });
    }
  }

  // set and check answer
  setAnswer (index, isCorrect) {
    if (this.state.currentAnswerIndex === null) {
      // check answer
      this.setState({
        currentAnswerIndex: index,
        currentAnswerCorrect: isCorrect,
        mode: 'question'
      });

      // submit answer
      if (!this.props.isOffline) {
        // only send answer for current question
        const payload = { userId: this.state.userId };

        payload[`answerQ${this.state.currentQuestion + 1}`] = this.state.currentAnswerIndex + 1;
        api.post(config.api.create, payload, this.state.token).then(() => this.getUserVotes());
      } else {
        this.getUserVotes();
      }
    }
  }

  // get user votes from api
  getUserVotes () {
    if (!this.props.isOffline) {
      api.get(config.api.proportions, { question: this.state.currentQuestion + 1 }).then(
        json => this.setState({ voteRatios: [ json.anteile.richtig, json.anteile.falsch ] })
      );
    } else {
      this.setState({ voteRatios: [] });
    }
  }

  // initial setup
  setup () {
    if (!this.props.isOffline) {
      this.setState({ isFetching: true });

      api.getToken().then(accessToken => {
        this.setState({ token: accessToken });

        // create user
        api.createUser(accessToken)
          .then(user => {
            this.setState({ userId: user.userId, isFetching: false });
            this.jumpTo();
          });
      });
    }
  }

  // shortcut: jump to specific screen using `#{something}`
  jumpTo () {
    if (window.location.hash) {
      const hashInfo = window.location.hash.replace('#', '').split('_');

      this.setState({
        route: 'question',
        mode: hashInfo[0],
        currentAmount: 0,
        currentAnswerCorrect: null,
        currentAnswerIndex: null,
        currentNumberOfPoints: 1000,
        currentQuestion: parseInt(hashInfo[1], 10),
        nextNumberOfPoints: 200,
        voteRatios: null
      });
    }
  }

  // set navigation state
  navigate (route) {
    this.setState({ route });
  }

  // finish user session
  endUserSession () {
    api.endSession(this.state.userId, this.state.token);
  }

  // reset everything to restart the module
  reset () {
    this.setState({ route: 'titlescreen' });
    this.setup();
  }

  // LIFECYLCE
  componentWillMount () {
    this.setup();
  }

  // RENDER
  render () {
    let outputContent;

    // get header content
    const total = fixedDigits(config.numberQuestions, 2);
    const index = this.state.currentQuestion + 1; // 0-indexed
    const headerState = `${fixedDigits(index, 2)}/${total}`;

    switch (this.state.route) {

      case 'question':
        outputContent = <QuestionScreen
          {...content}
          isOffline={this.props.isOffline}
          route={this.state.route}
          mode={this.state.mode}
          headerState={headerState}
          currentQuestion={this.state.currentQuestion}
          currentAnswerIndex={this.state.currentAnswerIndex}
          currentAnswerCorrect={this.state.currentAnswerCorrect}
          currentNumberOfPoints={this.state.currentNumberOfPoints}
          currentAmount={this.state.currentAmount}
          nextNumberOfPoints={this.state.nextNumberOfPoints}
          toNextQuestion={this.toNextQuestion}
          voteRatios={this.state.voteRatios}
          setAnswer={this.setAnswer} />;
        break;

      case 'finalscreen':
        outputContent = <FinalScreen
          {...content}
          navigate={this.navigate}
          isFetching={this.state.isFetching} />;
        break;

      case 'titlescreen':
      default:
        outputContent = <TitleScreen
          {...content}
          navigate={this.navigate}
          navigateTo='question'
          isFetching={this.state.isFetching} />;
        break;
    }

    return outputContent;
  }

}
