import React from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import Modal from 'react-modal'
import isEqual from 'lodash/isEqual'
import cloneDeep from 'lodash/cloneDeep'
import Admin from './../admin'
import Instance from './util/instance'
import ModalSelect from './modal-select'
import ReusableImages from './reusable-images'
import { fetchEntities, createEntity, updateEntity, deleteEntity } from '../actions/index'
import { ReusableImagesModalStyles, SelectModalStyles, NotificationModalStyles, MarkdownModalStyles } from './helpers/modal-styles'
import { withExitPrompt } from './util/with-exit-prompt'

interface PagePartialType {
  id?: number;
  fieldsCount?: number;
  name?: string;
  visible?: boolean;
}

interface PagePartialField {
  id: number;
}

interface PagePartialProps {
  contentDownloads: any[];
  createEntity: any;
  deleteEntity: any;
  deletePagePartial: any;
  deleteNestedPagePartial: any;
  errors: string[];
  eventSeries: any[];
  fetchEntities: any;
  fields: PagePartialField[];
  files: any[];
  headerTypes: any[];
  images: any[];
  instances: any[];
  index: number;
  nested: boolean;
  nestedPagePartials: any[];
  pagePartial: PagePartialType;
  parentPartialFieldId: number;
  partials: any[];
  passedPagePartial: any;
  transcripts: any[];
  webinars: any[];
  updateEntity: any;
}

interface PagePartialState extends ComponentState {
  contentDownloads: any[];
  copyModalOpen: boolean;
  eventSeries: any[];
  fetching: boolean;
  fields: PagePartialField[];
  files: any[];
  headerTypes: any[];
  images: any[];
  instances: any[];
  isExpanded: boolean;
  markdownModalOpen: boolean;
  nestedPagePartials: PagePartialType[];
  notificationModalOpen: boolean;
  notificationPageId: number;
  notificationType: string;
  pagePartial: PagePartialType;
  pagePartialSaved: PagePartialType;
  partialsModalOpen: boolean;
  reusableImagesModalOpen: boolean;
  transcripts: any[];
  webinars: any[];
}

class PagePartial extends React.Component<PagePartialProps, PagePartialState> {

  constructor(props) {
    super(props);

    this.state = {
      contentDownloads: [],
      copyModalOpen: false,
      errors: [],
      eventSeries: [],
      fetching: false,
      fields: [],
      files: [],
      headerTypes: [],
      images: [],
      instances: [],
      isExpanded: false,
      markdownModalOpen: false,
      nestedPagePartials: [],
      notificationModalOpen: false,
      notificationPageId: null,
      notificationType: null,
      pagePartial: {},
      pagePartialSaved: {},
      partialsModalOpen: false,
      reusableImagesModalOpen: false,
      transcripts: [],
      webinars: []
    }
  }

  componentDidMount() {
    this.setState({
      pagePartial: this.props.passedPagePartial
    });
  }

  checkForChanges() {
    return !isEqual(this.state.pagePartial, this.state.pagePartialSaved);
  }

  changeFieldArgs() {
    return {
      thing: "pagePartial",
      errorsArray: this.state.errors,
      changesFunction: this.checkForChanges.bind(this)
    }
  }

  mouseDownHandler(e) {
    $('.handle').addClass('grabbing');
    e.target.parentElement.classList.add('dragging-this');
  }

  mouseUpHandler(e) {
    $('.handle').removeClass('grabbing');
    e.target.parentElement.classList.remove('dragging-this');
  }

  clickDelete() {
    if (this.props.nested) {
      this.props.deleteNestedPagePartial(this.props.parentPartialFieldId);
    } else {
      this.props.deletePagePartial(this.state.pagePartial.id);
    }
  }

  clickCopy() {
    this.setState({
      copyModalOpen: true
    });
  }

  clickArrow() {
    const isExpanded = !this.state.isExpanded;
    const needToFetch = (isExpanded && this.state.fields.length === 0);
    this.setState({
      fetching: needToFetch,
      isExpanded
    }, () => {
      if (needToFetch) {
        this.props.fetchEntities({
          url: `/admin/api/page_partials/${this.state.pagePartial.id}`
        }).then(() => {
          this.setState({
            fetching: false,
            fields: this.props.fields,
            pagePartial: this.props.pagePartial,
            pagePartialSaved: cloneDeep(this.props.pagePartial),
            images: this.props.images,
            files: this.props.files,
            instances: this.props.instances,
            nestedPagePartials: this.props.nestedPagePartials,
            webinars: this.props.webinars,
            headerTypes: this.props.headerTypes
          }, () => {
            Instance.fetchAdditionalNeededData.call(this, { entityName: 'pagePartial', addingEntity: false });
          });
        });
      } else {
        Admin.setUpNiceSelect({
          selector: 'select',
          func: Admin.changeField.bind(this, this.changeFieldArgs()),
          adjustWidthSelector: '.instance-fields .nice-select'
        });
      }
    });
  }

  clickSave() {
    this.setState({
      fetching: true,
      justSaved: true
    }, () => {
      this.props.updateEntity({
        id: this.state.pagePartial.id,
        directory: 'page_partials',
        entityName: 'pagePartial',
        entity: this.state.pagePartial
      }).then(() => {
        this.setState({
          fetching: false,
          pagePartial: this.props.pagePartial,
          pagePartialSaved: cloneDeep(this.props.pagePartial),
          changesToSave: false
        });
      }, () => {
        this.setState({
          fetching: false,
          errors: this.props.errors
        });
      });
    });
  }

  addNestedPagePartial(args) {
    const { partialId, partialFieldId } = args;
    const pagePartialFieldId = this.state.pagePartial[`${partialFieldId}_page_partial_field_id`];
    this.setState({
      fetching: true
    });
    this.props.createEntity({
      directory: 'page_partials/create_nested',
      entityName: 'pagePartial',
      entity: {
        page_partial_field_id: pagePartialFieldId,
        partial_id: partialId,
        parent_id: this.state.pagePartial.id
      }
    }).then(() => {
      this.setState({
        fetching: false,
        pagePartial: this.props.pagePartial,
        nestedPagePartials: this.props.nestedPagePartials
      });
    });
  }

  deleteNestedPagePartial(fieldId) {
    let pagePartialFieldId = this.state.pagePartial[`${fieldId}_page_partial_field_id`];
    this.setState({
      fetching: true
    });
    this.props.deleteEntity({
      directory: 'page_partials/delete_nested',
      id: 1,
      data: {
        parentId: this.state.pagePartial.id,
        pagePartialFieldId
      },
      callback: (response) => {
        const { pagePartial, nestedPagePartials } = response;
        this.setState({
          fetching: false,
          pagePartial,
          nestedPagePartials
        });
      }
    });
  }

  selectPage(e) {
    let pageId = e.target.dataset.id;
    this.setState({
      copyModalOpen: false,
      notificationModalOpen: true,
      notificationType: "wait",
      notificationPageId: pageId
    });
    // TODO: after converting to redux, make this an action:
    let pagePartial = this.state.pagePartial;
    $.ajax({
      method: 'POST',
      url: '/admin/api/page_partials/copy',
      data: {
        page_partial_id: pagePartial.id,
        page_id: pageId
      },
      success: (response) => {
        this.setState({
          notificationType: 'success'
        });
      }
    });
  }

  render() {
    return(
      <div id={ "partial-" + this.state.pagePartial.id } className="page-partial clearfix" data-index={ this.props.index }>
        { Admin.renderGrayedOut(this.state.fetching) }
        { Admin.renderSpinner(this.state.fetching) }
        { this.renderArrowAndButtons() }
        <h2 className={ "page-partial-name" + (this.state.pagePartial.visible ? "" : " not-visible") }>{ this.state.pagePartial.name }</h2>
        { this.state.isExpanded ? this.renderExpandedPartial() : '' }
        <Modal isOpen={ this.state.reusableImagesModalOpen } onRequestClose={ Admin.closeModals.bind(this) } contentLabel="Modal" style={ ReusableImagesModalStyles }>
          <ReusableImages
            entityName="pagePartial"
            closeModal={ Admin.closeModals.bind(this) }
            receiveReusableImageFunction={ Instance.selectReusableImage.bind(this) }
          />
        </Modal>
        <Modal isOpen={ this.state.copyModalOpen } onRequestClose={ Admin.closeModals.bind(this) } contentLabel="Modal" style={ SelectModalStyles }>
          <ModalSelect header="Copy partial to which page?" fetchOptions="pages" property="name" func={ this.selectPage.bind(this) } />
        </Modal>
        <Modal isOpen={ this.state.notificationModalOpen } onRequestClose={ Admin.closeModals.bind(this) } contentLabel="Modal" style={ NotificationModalStyles }>
          { this.renderNotification() }
        </Modal>
        <Modal isOpen={ this.state.markdownModalOpen } onRequestClose={ Admin.closeModals.bind(this) } contentLabel="Modal" style={ MarkdownModalStyles }>
          <div className="markdown-syntax-guide">
            <h1>Markdown Syntax</h1>
            <table>
              <thead>
                <tr>
                  <th>Style</th>
                  <th>Markdown Syntax</th>
                  <th>Example</th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td>Bold</td>
                  <td><code>**</code> or <code>__</code></td>
                  <td><code>**bold text**</code></td>
                </tr>
                <tr>
                  <td>H1</td>
                  <td><code>#</code></td>
                  <td><code># Header</code></td>
                </tr>
                <tr>
                  <td>H2</td>
                  <td><code>##</code></td>
                  <td><code>## Header</code></td>
                </tr>
                <tr>
                  <td>H3</td>
                  <td><code>###</code></td>
                  <td><code>### Header</code></td>
                </tr>
                <tr>
                  <td>H4</td>
                  <td><code>####</code></td>
                  <td><code>#### Header</code></td>
                </tr>
                <tr>
                  <td>H5</td>
                  <td><code>#####</code></td>
                  <td><code>##### Header</code></td>
                </tr>
                <tr>
                  <td>H6</td>
                  <td><code>######</code></td>
                  <td><code>###### Header</code></td>
                </tr>
                <tr>
                  <td>Image</td>
                  <td><code>![]()</code></td>
                  <td><code>![alt text](images/foo.jpg)</code></td>
                </tr>
                <tr>
                  <td>Italic</td>
                  <td><code>*</code></td>
                  <td><code>*italic text*</code></td>
                </tr>
                <tr>
                  <td>Horizontal Rule</td>
                  <td><code>---</code> or <code>***</code> or <code>___</code></td>
                  <td><code>---</code></td>
                </tr>
                <tr>
                  <td>Link</td>
                  <td><code>[]()</code></td>
                  <td><code>[visit Teachable](https://teachable.com)</code></td>
                </tr>
                <tr>
                  <td>List (Bullet)</td>
                  <td><code>*</code> or <code>-</code> or <code>+</code></td>
                  <td><code>* first item</code><br /><code>* second item</code></td>
                </tr>
                <tr>
                  <td>Superscript</td>
                  <td><code>^</code></td>
                  <td><code>^superscript</code></td>
                </tr>
              </tbody>
            </table>
          </div>
        </Modal>
      </div>
    );
  }

  renderArrowAndButtons() {
    return (
      <div>
        <img className="trash-can" src={ window.Images.trashCan } onClick={ this.clickDelete.bind(this) } />
        <div className="copy" onClick={ this.clickCopy.bind(this) }></div>
        { this.renderHandle() }
        { this.renderExpandToggle(this.state.pagePartial.fieldsCount, this.state.isExpanded) }
      </div>
    );
  }

  renderHandle() {
    if (this.props.nested) {
      return null;
    } else {
      return(
        <img className="handle" src={ window.Images.handle } onMouseDown={ this.mouseDownHandler.bind(this) } onMouseUp={ this.mouseUpHandler.bind(this) } />
      );
    }
  }

  renderExpandToggle(fieldsCount, isExpanded) {
    if (fieldsCount > 0) {
      return (
        <img className={ "expand-toggle" + (isExpanded ? " expanded" : "") } src={ window.Images.grayTriangle } onClick={ this.clickArrow.bind(this) } />
      );
    } else {
      return (
        <div className="expand-toggle-placeholder"></div>
      );
    }
  }

  renderExpandedPartial() {
    return([
      <div key="1">
        { this.renderFields() }
      </div>,
      <a key="2" className={ "orange-button standard-button-width btn" + Admin.renderDisabledButtonClass(this.state.fetching || !this.state.changesToSave) } onClick={ this.clickSave.bind(this) }>
        { Admin.saveButtonText.call(this) }
      </a>,
      <div key="3">
        <a onClick={ this.clickArrow.bind(this) } className="link-below-field">Close Partial</a>
      </div>
    ]);
  }

  renderFields() {
    if (this.state.fields.length > 0) {
      return Instance.renderFields.call(this, {
        fields: this.state.fields,
        entityName: 'pagePartial'
      });
    } else {
      return <div className={ "instance-fields" + (this.state.fetching ? " fetching" : "") }></div>;
    }
  }

  renderNotification() {
    switch (this.state.notificationType) {
      case "wait":
        return(
          <div className="notification">
            <h1>Copying Partial...</h1>,
            <img src={ window.Images.spinner } />
          </div>
        );
        break;
      case "success":
        return(
          <div className="notification">
            <h1>Partial Copied.</h1>
            <a target="_blank" href={ `/admin/pages/${this.state.notificationPageId}` }>Visit Page</a>
          </div>
        );
        break;
      default:
        return null;
    }
  }

  componentDidUpdate() {
    $('.match-height-layout').matchHeight();
  }
}

const mapStateToProps = (reducers, props) => {
  return reducers.standardReducer;
};

function mapDispatchToProps(dispatch) {
  return bindActionCreators({ fetchEntities, createEntity, updateEntity, deleteEntity }, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(withExitPrompt(PagePartial));
