/* eslint-env browser */

import React from "react";
import { apiRequest, loadData, getPlatform } from "../utils";
import i18n from "../i18n";
import hub from "../hub";
import { AttachmentsChangedEvent } from "../events";
import RecordComponent from "./RecordComponent";
import Link from "../components/Link";
import makeRichPromise from "../richPromise";

const getBrowseButtonTitle = () => {
  const platform = getPlatform();
  if (platform === "mac") {
    return i18n.trans("BROWSE_FS_MAC");
  } else if (platform === "windows") {
    return i18n.trans("BROWSE_FS_WINDOWS");
  } else {
    return i18n.trans("BROWSE_FS");
  }
};

const CHILDREN_PER_PAGE = 15;

class ChildPosCache {
  constructor() {
    this.memo = [];
  }

  rememberPosition(record, page) {
    for (let i = 0; i < this.memo.length; i++) {
      if (this.memo[i][0] === record) {
        this.memo[i][1] = page;
        return;
      }
    }
    this.memo.unshift([record, page]);
    if (this.memo.length > 5) {
      this.memo.length = 5;
    }
  }

  getPosition(record, childCount) {
    for (let i = 0; i < this.memo.length; i++) {
      if (this.memo[i][0] === record) {
        let rv = this.memo[i][1];
        if (childCount !== undefined) {
          rv = Math.min(rv, Math.ceil(childCount / CHILDREN_PER_PAGE));
        }
        return rv;
      }
    }
    return 1;
  }
}

class Sidebar extends RecordComponent {
  constructor(props) {
    super(props);

    this.state = this._getInitialState();
    this.childPosCache = new ChildPosCache();
    this.onAttachmentsChanged = this.onAttachmentsChanged.bind(this);
  }

  _getInitialState() {
    return {
      recordAttachments: [],
      recordChildren: [],
      recordAlts: [],
      canHaveAttachments: false,
      canHaveChildren: false,
      isAttachment: false,
      canBeDeleted: false,
      recordExists: false,
      lastRecordRequest: null,
      childrenPage: 1,
    };
  }

  componentDidMount() {
    super.componentDidMount();
    this._updateRecordInfo();

    hub.subscribe(AttachmentsChangedEvent, this.onAttachmentsChanged);
  }

  componentDidUpdate(prevProps, prevState) {
    super.componentDidUpdate(prevProps, prevState);
    if (prevProps.match.params.path !== this.props.match.params.path) {
      this._updateRecordInfo();
    }
  }

  componentWillUnmount() {
    super.componentWillUnmount();
    hub.unsubscribe(AttachmentsChangedEvent, this.onAttachmentsChanged);
  }

  onAttachmentsChanged(event) {
    if (event.recordPath === this.getRecordPath()) {
      this._updateRecordInfo();
    }
  }

  _updateRecordInfo() {
    const path = this.getRecordPath();
    if (path === null) {
      this.setState(this._getInitialState());
      return;
    }

    this.setState(
      {
        lastRecordRequest: path,
      },
      () => {
        loadData("/recordinfo", { path: path }, null, makeRichPromise).then(
          (resp) => {
            // we're already fetching something else.
            if (path !== this.state.lastRecordRequest) {
              return;
            }
            const alts = resp.alts;
            alts.sort((a, b) => {
              const nameA =
                (a.is_primary ? "A" : "B") + i18n.trans(a.name_i18n);
              const nameB =
                (b.is_primary ? "A" : "B") + i18n.trans(b.name_i18n);
              return nameA === nameB ? 0 : nameA < nameB ? -1 : 1;
            });
            this.setState({
              recordAttachments: resp.attachments,
              recordChildren: resp.children,
              recordAlts: alts,
              canHaveAttachments: resp.can_have_attachments,
              canHaveChildren: resp.can_have_children,
              isAttachment: resp.is_attachment,
              canBeDeleted: resp.can_be_deleted,
              recordExists: resp.exists,
              childrenPage: this.childPosCache.getPosition(
                path,
                resp.children.length
              ),
            });
          }
        );
      }
    );
  }

  fsOpen(event) {
    event.preventDefault();
    apiRequest(
      "/browsefs",
      {
        data: {
          path: this.getRecordPath(),
          alt: this.getRecordAlt(),
        },
        // eslint-disable-next-line indent
        method: "POST",
      },
      makeRichPromise
    ).then((resp) => {
      if (!resp.okay) {
        alert(i18n.trans("ERROR_CANNOT_BROWSE_FS"));
      }
    });
  }

  renderPageActions() {
    const urlPath = this.getUrlRecordPathWithAlt();
    const links = [];
    const deleteLink = null;

    links.push(
      <li key="edit">
        <Link to={`${urlPath}/edit`}>
          {this.state.isAttachment
            ? i18n.trans("EDIT_METADATA")
            : i18n.trans("EDIT")}
        </Link>
      </li>
    );

    if (this.state.canBeDeleted) {
      links.push(
        <li key="delete">
          <Link to={`${urlPath}/delete`}>{i18n.trans("DELETE")}</Link>
        </li>
      );
    }

    links.push(
      <li key="preview">
        <Link to={`${urlPath}/preview`}>{i18n.trans("PREVIEW")}</Link>
      </li>
    );

    if (this.state.recordExists) {
      links.push(
        <li key="fs-open">
          <a href="#" onClick={this.fsOpen.bind(this)}>
            {getBrowseButtonTitle()}
          </a>
        </li>
      );
    }

    if (this.state.canHaveChildren) {
      links.push(
        <li key="add-child">
          <Link to={`${urlPath}/add-child`}>
            {i18n.trans("ADD_CHILD_PAGE")}
          </Link>
        </li>
      );
    }

    if (this.state.canHaveAttachments) {
      links.push(
        <li key="add-attachment">
          <Link to={`${urlPath}/upload`}>{i18n.trans("ADD_ATTACHMENT")}</Link>
        </li>
      );
    }

    const title = this.state.isAttachment
      ? i18n.trans("ATTACHMENT_ACTIONS")
      : i18n.trans("PAGE_ACTIONS");

    return (
      <div key="actions" className="section">
        <h3>{title}</h3>
        <ul className="nav">
          {links}
          {deleteLink}
        </ul>
      </div>
    );
  }

  renderAlts() {
    if (this.state.recordAlts.length < 2) {
      return null;
    }

    const items = this.state.recordAlts.map((item) => {
      let title = i18n.trans(item.name_i18n);
      let className = "alt";
      if (item.is_primary) {
        title += " (" + i18n.trans("PRIMARY_ALT") + ")";
      } else if (item.primary_overlay) {
        title += " (" + i18n.trans("PRIMARY_OVERLAY") + ")";
      }
      if (!item.exists) {
        className += " alt-missing";
      }

      const path = this.getPathToAdminPage(null, {
        path: this.getUrlRecordPathWithAlt(null, item.alt),
      });
      return (
        <li key={item.alt} className={className}>
          <Link to={path}>{title}</Link>
        </li>
      );
    });

    return (
      <div key="alts" className="section">
        <h3>{i18n.trans("ALTS")}</h3>
        <ul className="nav">{items}</ul>
      </div>
    );
  }

  renderChildPagination() {
    const pages = Math.ceil(
      this.state.recordChildren.length / CHILDREN_PER_PAGE
    );
    if (pages <= 1) {
      return null;
    }
    const page = this.state.childrenPage;
    const goToPage = (diff, event) => {
      event.preventDefault();
      const newPage = page + diff;
      this.childPosCache.rememberPosition(this.getRecordPath(), newPage);
      this.setState({
        childrenPage: newPage,
      });
    };

    return (
      <li className="pagination">
        {page > 1 ? (
          <a href="#" onClick={goToPage.bind(this, -1)}>
            «
          </a>
        ) : (
          <em>«</em>
        )}
        <span className="page">{page + " / " + pages}</span>
        {page < pages ? (
          <a href="#" onClick={goToPage.bind(this, +1)}>
            »
          </a>
        ) : (
          <em>»</em>
        )}
      </li>
    );
  }

  renderChildActions() {
    const target =
      this.props.match.params.page === "preview" ? "preview" : "edit";

    const children = this.state.recordChildren.slice(
      (this.state.childrenPage - 1) * CHILDREN_PER_PAGE,
      this.state.childrenPage * CHILDREN_PER_PAGE
    );

    const items = children.map((child) => {
      const urlPath = this.getUrlRecordPathWithAlt(child.path);
      return (
        <li key={child.id}>
          <Link to={`${urlPath}/${target}`}>
            {i18n.trans(child.label_i18n)}
          </Link>
        </li>
      );
    });

    if (items.length === 0) {
      items.push(
        <li key="_missing">
          <em>{i18n.trans("NO_CHILD_PAGES")}</em>
        </li>
      );
    }

    return (
      <div key="children" className="section">
        <h3>{i18n.trans("CHILD_PAGES")}</h3>
        <ul className="nav record-children">
          {this.renderChildPagination()}
          {items}
        </ul>
      </div>
    );
  }

  renderAttachmentActions() {
    const items = this.state.recordAttachments.map((atch) => {
      const urlPath = this.getUrlRecordPathWithAlt(atch.path);
      return (
        <li key={atch.id}>
          <Link to={`${urlPath}/edit`}>
            {atch.id} ({atch.type})
          </Link>
        </li>
      );
    });

    if (items.length === 0) {
      items.push(
        <li key="_missing">
          <em>{i18n.trans("NO_ATTACHMENTS")}</em>
        </li>
      );
    }

    return (
      <div key="attachments" className="section">
        <h3>{i18n.trans("ATTACHMENTS")}</h3>
        <ul className="nav record-attachments">{items}</ul>
      </div>
    );
  }

  render() {
    const sections = [];

    if (this.getRecordPath() !== null) {
      sections.push(this.renderPageActions());
    }

    sections.push(this.renderAlts());

    if (this.state.canHaveChildren) {
      sections.push(this.renderChildActions());
    }

    if (this.state.canHaveAttachments) {
      sections.push(this.renderAttachmentActions());
    }

    return <div className="sidebar-wrapper">{sections}</div>;
  }
}

export default Sidebar;
