/*
Markdown controller to view and update journal entries.

@copyright (c) Copyright 2013-2017 Dorian Pula
@license AGPL v3
@author Dorian Pula [dorian.pula@amber-penguin-software.ca]
*/


import {h, Component} from 'preact';  /** @jsx h*/

import {connect} from 'preact-redux';
import PropTypes from 'prop-types';

import markdown from 'markdown-it';
import highlighter from 'highlight.js';
import {Button, Collapse} from 'reactstrap';
import FontAwesome from 'react-fontawesome';

import {fetchPage, savePage} from '../actions';
import appStore from '../store';
import {withRouter} from 'react-router-dom';

import CodeMirror from './CodeEditor';


// # TODO Remove and rework to allow for two flags, rather than a single state?
export const EditorPaneState = {
  hidden: 0,
  editableClosed: 1,
  editableOpen: 2
};

export class MarkdownBlock extends Component {
  static get propTypes() {
    return {
      id: PropTypes.string,
      slug: PropTypes.string,
      content: PropTypes.string,
    }
  }

  render() {
    let md = markdown({
      html: true,
      highlight: (code_) => {
        return highlighter.highlightAuto(code_).value;
      }
    });
    let rawMarkup = md.render(this.props.content || '');

    return (
      <span id={ this.props.id } dangerouslySetInnerHTML={{__html: rawMarkup}} />
    );
  }
}


export class EditableMarkdownBlock extends Component {
  static get propTypes() {
    return {
      slug: PropTypes.string,
      article: PropTypes.string,
      title: PropTypes.string,
      editorTheme: PropTypes.string,
      location: PropTypes.object.isRequired,
      match: PropTypes.object,
      userCanEdit: PropTypes.bool
    }
  }

  constructor(props) {
    super(props);
    this.state = {
      displayContent: this.props.article || "Please wait while we load this page's entry.",
      originalContent: this.props.article || "Please wait while we load this page's entry.",
      editorPaneState: EditorPaneState.hidden
    };
    this.handleSaveContent = this.handleSaveContent.bind(this);
    this.handleToggleEditorPane = this.handleToggleEditorPane.bind(this);
    this.handleSaveContent = this.handleSaveContent.bind(this);
    this.handleResetContent = this.handleResetContent.bind(this);
    this.handleUpdateCode = this.handleUpdateCode.bind(this);
  }

  componentDidMount() {
    let pageToLoad = this.props.match.params.pageId;
    appStore.dispatch(fetchPage(pageToLoad));
    this.updateEditAllowance(this.props.userCanEdit);
  }

  componentWillReceiveProps(nextProps) {
    const {match} = this.props;
    if (match.params.pageId !== nextProps.match.params.pageId) {
      appStore.dispatch(fetchPage(nextProps.match.params.pageId));
    }
    this.setState({
      displayContent: nextProps.article,
      originalContent: nextProps.article,
    });
    this.updateEditAllowance(nextProps.userCanEdit)
  }

  handleUpdateCode(editor, metadata, newCode) {
    this.setState({displayContent: newCode});
  }

  handleToggleEditorPane() {
    let nextEditorState = this.state.editorPaneState;
    if (this.state.editorPaneState === EditorPaneState.editableOpen) {
      nextEditorState = EditorPaneState.editableClosed;
    }

    if (this.state.editorPaneState === EditorPaneState.editableClosed) {
      nextEditorState = EditorPaneState.editableOpen;
    }
    this.setState({editorPaneState: nextEditorState});
  }

  isEditorPaneOpen() {
    return this.state.editorPaneState === EditorPaneState.editableOpen;
  }

  handleResetContent() {
    this.setState({displayContent: this.state.originalContent});
  }

  handleSaveContent() {
    // # TODO Start using proper models for page and json
    let pageContent = {
      id: this.props.slug,
      title: this.props.title,
      content: this.state.displayContent
    };
    appStore.dispatch(savePage(pageContent));
  }

  updateEditAllowance(allowEdits) {
    let editorState = this.state.editorPaneState;
    if (!allowEdits) {
      editorState = EditorPaneState.hidden;
    }

    if (allowEdits && this.state.editorPaneState === EditorPaneState.hidden) {
      editorState = EditorPaneState.editableClosed;
    }
    this.setState({editorPaneState: editorState});
  }

  render() {
    // # TODO Factor the view into something nicer.
    let showEditorButton = (
      <Button onClick={ this.handleToggleEditorPane }>
        <FontAwesome name='edit'/> Edit
      </Button>
    );

    // # TODO Add in ability to display mhessages outside the collapsible pane
    let showPanel = (
      <Collapse isOpen={ this.isEditorPaneOpen() }>
        <CodeMirror
          value={ this.state.displayContent }
          onChange={ this.handleUpdateCode }
          options={{ mode: 'markdown', theme: this.props.editorTheme }} />
        <Button onClick={ this.handleSaveContent }>
          <FontAwesome name='save'/> Save
        </Button>
        <Button onClick={ this.handleResetContent }>
          <FontAwesome name='undo'/> Reset
        </Button>
      </Collapse>
    );

    if (this.state.editorPaneState === EditorPaneState.hidden) {
      showEditorButton = (<div />);
      showPanel = (<div />);
    }

    return (
      <div>
        <MarkdownBlock slug={ this.props.slug } content={ this.state.displayContent } />
        { showEditorButton }
        { showPanel }
      </div>
    );
  }
}

export const PageBlock = withRouter(
  connect(
    (state) => {
      return {
        'slug': state.page.slug,
        'article': state.page.content,
        'title': state.page.title,
        'editorTheme': state.editor.theme,
        'userCanEdit': state.user.token !== ''
      };
    })(EditableMarkdownBlock)
);
