import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { push } from 'connected-react-router';
import { connect } from 'react-redux';
import { drizzle } from '../index';

import PostList from '../components/PostList';
import NewPost from '../components/NewPost';
import FloatingButton from '../components/FloatingButton';

import { setNavBarTitle } from '../redux/actions/userInterfaceActions.js';

const contract = 'Forum';
const getTopicMethod = 'getTopic';

class TopicContainer extends Component {
  constructor(props) {
    super(props);

    // Topic ID should be a positive integer
    if (!/^[0-9]+$/.test(this.props.match.params.topicId)) {
      this.props.navigateTo('/404');
    }

    this.getBlockchainData = this.getBlockchainData.bind(this);
    this.fetchTopicSubject = this.fetchTopicSubject.bind(this);
    this.togglePostingState = this.togglePostingState.bind(this);
    this.postCreated = this.postCreated.bind(this);

    this.state = {
      pageStatus: 'initialized',
      topicID: parseInt(this.props.match.params.topicId),
      topicSubject: null,
      postFocus: this.props.match.params.postId
      && /^[0-9]+$/.test(this.props.match.params.postId)
        ? this.props.match.params.postId
        : null,
      fetchTopicSubjectStatus: 'pending',
      posting: false
    };
  }

  getBlockchainData() {
    if (this.state.pageStatus === 'initialized'
        && this.props.drizzleStatus.initialized) {
      this.dataKey = drizzle.contracts[contract].methods[getTopicMethod].cacheCall(
        this.state.topicID,
      );
      this.setState({
        pageStatus: 'loading'
      });
    }
    if (this.state.pageStatus === 'loading'
        && this.props.contracts[contract][getTopicMethod][this.dataKey]) {
      this.setState({
        pageStatus: 'loaded'
      });
      if (this.props.orbitDB.orbitdb !== null) {
        this.fetchTopicSubject(
          this.props.contracts[contract][getTopicMethod][this.dataKey].value[0],
        );
        this.setState({
          fetchTopicSubjectStatus: 'fetching'
        });
      }
    }
    if (this.state.pageStatus === 'loaded'
        && this.state.fetchTopicSubjectStatus === 'pending'
        && this.props.orbitDB.orbitdb !== null) {
      this.fetchTopicSubject(
        this.props.contracts[contract][getTopicMethod][this.dataKey].value[0],
      );
      this.setState({
        fetchTopicSubjectStatus: 'fetching'
      });
    }
  }

  async fetchTopicSubject(orbitDBAddress) {
    let orbitData;
    if (this.props.contracts[contract][getTopicMethod][this.dataKey].value[1]
        === this.props.user.address) {
      orbitData = this.props.orbitDB.topicsDB.get(this.state.topicID);
    } else {
      const fullAddress = `/orbitdb/${orbitDBAddress}/topics`;
      const store = await this.props.orbitDB.orbitdb.keyvalue(fullAddress);
      await store.load();

      const localOrbitData = store.get(this.state.topicID);
      if (localOrbitData) {
        orbitData = localOrbitData;
      } else {
        // Wait until we have received something from the network
        store.events.on('replicated', () => {
          orbitData = store.get(this.state.topicID);
        });
      }
    }

    this.props.setNavBarTitle(orbitData.subject);
    this.setState({
      topicSubject: orbitData.subject,
      fetchTopicSubjectStatus: 'fetched'
    });
  }

  togglePostingState(event) {
    if (event) {
      event.preventDefault();
    }
    this.setState(prevState => ({
      posting: !prevState.posting
    }));
  }

  postCreated() {
    this.setState(prevState => ({
      posting: false
    }));
  }

  render() {
    let topicContents;
    if (this.state.pageStatus === 'loaded') {
      topicContents = (
        (
          <div>
            <PostList
              postIDs={this.props.contracts[contract][getTopicMethod][this.dataKey].value[4]}
              focusOnPost={this.state.postFocus
                ? this.state.postFocus
                : null}
            />
            {this.state.posting
            && (
            <NewPost
              topicID={this.state.topicID}
              subject={this.state.topicSubject}
              postIndex={this.props.contracts[contract][getTopicMethod][this.dataKey].value[4].length}
              onCancelClick={() => { this.togglePostingState(); }}
              onPostCreated={() => { this.postCreated(); }}
            />
            )
            }
            <div className="posts-list-spacer" />
            {this.props.user.hasSignedUp && !this.state.posting
            && <FloatingButton onClick={this.togglePostingState} />
            }
          </div>
        )
      );
    }

    return (
      <div className="fill">
        {topicContents}
        {!this.state.posting
          && <div className="bottom-overlay-pad" />
          }
      </div>
    );
  }

  componentDidMount() {
    this.getBlockchainData();
  }

  componentDidUpdate() {
    this.getBlockchainData();
  }

  componentWillUnmount() {
    this.props.setNavBarTitle('');
  }
}

const mapDispatchToProps = dispatch => bindActionCreators({
  navigateTo: location => push(location),
  setNavBarTitle: navBarTitle => setNavBarTitle(navBarTitle)
}, dispatch);

const mapStateToProps = state => ({
  user: state.user,
  contracts: state.contracts,
  drizzleStatus: state.drizzleStatus,
  orbitDB: state.orbit
});

export default connect(mapStateToProps, mapDispatchToProps)(TopicContainer);