content: import _ from 'lodash';
  import {defineMessages, FormattedMessage, injectIntl} from 'react-intl';
  import {
    Button,
    Checkbox,
    Form,
    FormError,
    FormRow,
    FormRowGroup,
    FormRowItem,
    Select,
    SelectItem,
    Textbox,
  } from 'flood-ui-kit';
  import formatUtil from '@shared/util/formatUtil';
  import React from 'react';
  
  import Edit from '../../icons/Edit';
  import Close from '../../icons/Close';
  import EventTypes from '../../../constants/EventTypes';
  import FeedMonitorStore from '../../../stores/FeedMonitorStore';
  import ModalFormSectionHeader from '../ModalFormSectionHeader';
  import * as validators from '../../../util/validators';
  import UIActions from '../../../actions/UIActions';
  import connectStores from '../../../util/connectStores';
  
  const MESSAGES = defineMessages({
    mustSpecifyURL: {
      id: 'feeds.validation.must.specify.valid.feed.url',
      defaultMessage: 'You must specify a valid feed URL.',
    },
    mustSpecifyLabel: {
      id: 'feeds.validation.must.specify.label',
      defaultMessage: 'You must specify a label.',
    },
    intervalNotPositive: {
      id: 'feeds.validation.interval.not.positive',
      defaultMessage: 'The interval must be a positive integer.',
    },
    min: {
      id: 'feeds.time.min',
      defaultMessage: 'Minutes',
    },
    hr: {
      id: 'feeds.time.hr',
      defaultMessage: 'Hours',
    },
    day: {
      id: 'feeds.time.day',
      defaultMessage: 'Days',
    },
    url: {
      id: 'feeds.url',
      defaultMessage: 'URL',
    },
    label: {
      id: 'feeds.label',
      defaultMessage: 'Label',
    },
    interval: {
      id: 'feeds.interval',
      defaultMessage: 'Interval',
    },
    tags: {
      id: 'feeds.tags',
      defaultMessage: 'Tags',
    },
    search: {
      id: 'feeds.search',
      defaultMessage: 'Search term',
    },
  });
  
  const defaultFeed = {
    label: '',
    interval: 5,
    url: '',
  };
  
  class FeedsTab extends React.Component {
    formRef = null;
  
    manualAddingFormRef = null;
  
    validatedFields = {
      url: {
        isValid: validators.isURLValid,
        error: this.props.intl.formatMessage(MESSAGES.mustSpecifyURL),
      },
      label: {
        isValid: validators.isNotEmpty,
        error: this.props.intl.formatMessage(MESSAGES.mustSpecifyLabel),
      },
      interval: {
        isValid: validators.isPositiveInteger,
        error: this.props.intl.formatMessage(MESSAGES.intervalNotPositive),
      },
    };
  
    state = {
      errors: {},
      intervalmultipliers: [
        {
          displayName: this.props.intl.formatMessage(MESSAGES.min),
          value: 1,
        },
        {
          displayName: this.props.intl.formatMessage(MESSAGES.hr),
          value: 60,
        },
        {
          displayName: this.props.intl.formatMessage(MESSAGES.day),
          value: 1440,
        },
      ],
      currentlyEditingFeed: null,
      selectedFeed: null,
    };
  
    checkFieldValidity = _.throttle((fieldName, fieldValue) => {
      const {errors} = this.state;
  
      if (this.state.errors[fieldName] && this.validatedFields[fieldName].isValid(fieldValue)) {
        delete errors[fieldName];
        this.setState({errors});
      }
    }, 150);
  
    getAmendedFormData() {
      const formData = this.formRef.getFormData();
      formData.interval = (formData.interval * formData.intervalMultiplier).toString();
      delete formData.intervalMultiplier;
  
      return formData;
    }
  
    getIntervalSelectOptions() {
      return this.state.intervalmultipliers.map(interval => (
        <SelectItem key={interval.value} id={interval.value}>
          {interval.displayName}
        </SelectItem>
      ));
    }
  
    getAvailableFeedsOptions() {
      const {feeds} = this.props;
  
      if (!feeds.length) {
        return [
          <SelectItem key="empty" id="placeholder" placeholder>
            <em>
              <FormattedMessage id="feeds.no.feeds.available" defaultMessage="No feeds available." />
            </em>
          </SelectItem>,
        ];
      }
  
      return feeds.reduce(
        (feedOptions, feed) =>
          feedOptions.concat(
            <SelectItem key={feed._id} id={feed._id}>
              {feed.label}
            </SelectItem>,
          ),
        [
          <SelectItem key="select-feed" id="placeholder" placeholder>
            <em>
              <FormattedMessage id="feeds.select.feed" defaultMessage="Select feed" />
            </em>
          </SelectItem>,
        ],
      );
    }
  
    getModifyFeedForm(feed) {
      const isDayInterval = feed.interval % 1440;
      const minutesDivisor = feed.interval % 60 ? 1 : 60;
      const defaultIntervalTextValue = feed.interval / isDayInterval ? minutesDivisor : 1440;
      const defaultIntervalMultiplierId = isDayInterval ? minutesDivisor : 1440;
  
      return (
        <FormRowGroup>
          <FormRow>
            <Textbox
              id="label"
              label={this.props.intl.formatMessage(MESSAGES.label)}
              placeholder={this.props.intl.formatMessage(MESSAGES.label)}
              defaultValue={feed.label}
            />
            <Textbox
              id="interval"
              label={this.props.intl.formatMessage({
                id: 'feeds.select.interval',
                defaultMessage: 'Interval',
              })}
              placeholder={this.props.intl.formatMessage(MESSAGES.interval)}
              defaultValue={defaultIntervalTextValue}
              width="one-eighth"
            />
            <Select labelOffset defaultID={defaultIntervalMultiplierId} id="intervalMultiplier" width="one-eighth">
              {this.getIntervalSelectOptions()}
            </Select>
          </FormRow>
          <FormRow>
            <Textbox
              id="url"
              label={this.props.intl.formatMessage({
                id: 'feeds.url',
                defaultMessage: 'URL',
              })}
              placeholder={this.props.intl.formatMessage(MESSAGES.url)}
              defaultValue={feed.url}
            />
            <Button labelOffset onClick={() => this.setState({currentlyEditingFeed: null})}>
              <FormattedMessage id="button.cancel" defaultMessage="Cancel" />
            </Button>
            <Button labelOffset type="submit">
              <FormattedMessage id="button.save.feed" defaultMessage="Save" />
            </Button>
          </FormRow>
        </FormRowGroup>
      );
    }
  
    getFeedsListItem(feed) {
      const matchedCount = feed.count || 0;
      return (
        <li className="interactive-list__item interactive-list__item--stacked-content feed-list__feed" key={feed._id}>
          <div className="interactive-list__label">
            <ul className="interactive-list__detail-list">
              <li
                className="interactive-list__detail-list__item
                interactive-list__detail--primary">
                {feed.label}
              </li>
              <li
                className="interactive-list__detail-list__item
                interactive-list__detail-list__item--overflow
                interactive-list__detail interactive-list__detail--secondary">
                <FormattedMessage
                  id="feeds.match.count"
                  defaultMessage="{count, plural, =1 {# match} other
                    {# matches}}"
                  values={{count: matchedCount}}
                />
              </li>
              {feed === this.state.currentlyEditingFeed && (
                <li
                  className="interactive-list__detail-list__item
                interactive-list__detail--primary">
                  Modifying
                </li>
              )}
            </ul>
            <ul className="interactive-list__detail-list">
              <li
                className="interactive-list__detail-list__item
                interactive-list__detail interactive-list__detail--tertiary">
                {formatUtil.minToHumanReadable(feed.interval)}
              </li>
              <li
                className="interactive-list__detail-list__item
                interactive-list__detail-list__item--overflow
                interactive-list__detail interactive-list__detail--tertiary">
                <a href={feed.url} rel="noopener noreferrer" target="_blank">
                  {feed.url}
                </a>
              </li>
            </ul>
          </div>
          <span
            className="interactive-list__icon interactive-list__icon--action"
            onClick={() => this.handleModifyFeedClick(feed)}>
            <Edit />
          </span>
          <span
            className="interactive-list__icon interactive-list__icon--action interactive-list__icon--action--warning"
            onClick={() => this.handleRemoveFeedClick(feed)}>
            <Close />
          </span>
        </li>
      );
    }
  
    getFeedAddForm(errors) {
      return (
        <Form
          className="inverse"
          onChange={this.handleFormChange}
          onSubmit={this.handleFormSubmit}
          ref={ref => {
            this.formRef = ref;
          }}>
          <ModalFormSectionHeader>
            <FormattedMessage id="feeds.existing.feeds" defaultMessage="Existing Feeds" />
          </ModalFormSectionHeader>
          {errors}
          <FormRow>
            <FormRowItem>{this.getFeedsList()}</FormRowItem>
          </FormRow>
          {this.state.currentlyEditingFeed ? (
            this.getModifyFeedForm(this.state.currentlyEditingFeed)
          ) : (
            <FormRow>
              <FormRowItem width="auto" />
              <Button onClick={() => this.handleAddFeedClick()}>
                <FormattedMessage id="button.new" defaultMessage="New" />
              </Button>
            </FormRow>
          )}
        </Form>
      );
    }
  
    getFeedsList() {
      const {feeds} = this.props;
  
      if (feeds.length === 0) {
        return (
          <ul className="interactive-list">
            <li className="interactive-list__item">
              <FormattedMessage defaultMessage="No feeds defined." id="feeds.no.feeds.defined" />
            </li>
          </ul>
        );
      }
  
      const feedsList = feeds.map(feed => this.getFeedsListItem(feed));
  
      return <ul className="interactive-list feed-list">{feedsList}</ul>;
    }
  
    getFeedItemsForm() {
      return (
        <Form
          className="inverse"
          onChange={this.handleBrowseFeedChange}
          onSubmit={this.handleBrowseFeedSubmit}
          ref={ref => {
            this.manualAddingFormRef = ref;
          }}>
          <ModalFormSectionHeader>
            <FormattedMessage id="feeds.browse.feeds" defaultMessage="Browse feeds" />
          </ModalFormSectionHeader>
          <FormRow>
            <Select
              disabled={!this.props.feeds.length}
              grow={false}
              id="feedID"
              label={this.props.intl.formatMessage({
                id: 'feeds.select.feed',
                defaultMessage: 'Select feed',
              })}
              width="three-eighths">
              {this.getAvailableFeedsOptions()}
            </Select>
            {this.renderSearchField()}
            {this.renderDownloadButton()}
          </FormRow>
          {this.state.selectedFeed && <FormRow>{this.getFeedItemsList()}</FormRow>}
        </Form>
      );
    }
  
    getFeedItemsList() {
      const {items} = this.props;
  
      if (items.length === 0) {
        return (
          <ul className="interactive-list">
            <li className="interactive-list__item">
              <div className="interactive-list__label">
                <FormattedMessage defaultMessage="No items matching search term." id="feeds.no.items.matching" />
              </div>
            </li>
          </ul>
        );
      }
  
      const itemsList = items.map((item, index) => (
        <li className="interactive-list__item interactive-list__item--stacked-content feed-list__feed" key={item.title}>
          <div className="interactive-list__label feed-list__feed-label">{item.title}</div>
          <Checkbox id={index} />
        </li>
      ));
  
      return <ul className="interactive-list feed-list">{itemsList}</ul>;
    }
  
    handleFormSubmit = () => {
      const {errors, isValid} = this.validateForm();
  
      if (!isValid) {
        this.setState({errors});
      } else {
        const currentFeed = this.state.currentlyEditingFeed;
        const formData = this.getAmendedFormData();
  
        if (currentFeed === defaultFeed) {
          FeedMonitorStore.addFeed(formData);
        } else {
          FeedMonitorStore.modifyFeed(currentFeed._id, formData);
        }
        this.formRef.resetForm();
        this.setState({currentlyEditingFeed: null});
      }
    };
  
    handleFormChange = ({event, formData}) => {
      this.checkFieldValidity(event.target.name, formData[event.target.name]);
    };
  
    handleRemoveFeedClick = feed => {
      FeedMonitorStore.removeFeed(feed._id);
  
      if (feed === this.state.currentlyEditingFeed) {
        this.setState({currentlyEditingFeed: null});
      }
    };
  
    handleAddFeedClick = () => {
      this.setState({currentlyEditingFeed: defaultFeed});
    };
  
    handleModifyFeedClick = feed => {
      this.setState({currentlyEditingFeed: feed});
    };
  
    handleBrowseFeedChange = input => {
      if (input.event.target.type !== 'checkbox') {
        this.setState({selectedFeed: input.formData.feedID});
        FeedMonitorStore.fetchItems({params: {id: input.formData.feedID, search: input.formData.search}});
      }
    };
  
    handleBrowseFeedSubmit = () => {
      const formData = this.manualAddingFormRef.getFormData();
  
      const downloadedTorrents = this.props.items
        .filter((item, index) => formData[index])
        .map((torrent, index) => ({id: index, value: torrent.link}));
  
      UIActions.displayModal({id: 'add-torrents', torrents: downloadedTorrents});
    };
  
    validateForm() {
      const formData = this.formRef.getFormData();
      const errors = Object.keys(this.validatedFields).reduce((memo, fieldName) => {
        const fieldValue = formData[fieldName];
  
        if (!this.validatedFields[fieldName].isValid(fieldValue)) {
          memo[fieldName] = this.validatedFields[fieldName].error;
        }
  
        return memo;
      }, {});
  
      return {errors, isValid: !Object.keys(errors).length};
    }
  
    renderSearchField = () => {
      const {selectedFeed} = this.state;
  
      if (selectedFeed == null) return null;
  
      return (
        <Textbox
          id="search"
          label={this.props.intl.formatMessage({
            id: 'feeds.search.term',
            defaultMessage: 'Search term',
          })}
          placeholder={this.props.intl.formatMessage(MESSAGES.search)}
        />
      );
    };
  
    renderDownloadButton = () => {
      const {selectedFeed} = this.state;
  
      if (selectedFeed == null) return null;
  
      return (
        <Button key="button" type="submit" labelOffset>
          <FormattedMessage id="button.download" defaultMessage="Download" />
        </Button>
      );
    };
  
    render() {
      const errors = Object.keys(this.state.errors).map(errorID => (
        <FormRow key={errorID}>
          <FormError>{this.state.errors[errorID]}</FormError>
        </FormRow>
      ));
      return (
        <div>
          {this.getFeedAddForm(errors)}
          {this.getFeedItemsForm()}
        </div>
      );
    }
  }
  
  const ConnectedFeedsTab = connectStores(injectIntl(FeedsTab), () => {
    return [
      {
        store: FeedMonitorStore,
        event: EventTypes.SETTINGS_FEED_MONITORS_FETCH_SUCCESS,
        getValue: ({store}) => {
          return {
            feeds: store.getFeeds(),
          };
        },
      },
      {
        store: FeedMonitorStore,
        event: EventTypes.SETTINGS_FEED_MONITOR_ITEMS_FETCH_SUCCESS,
        getValue: ({store}) => {
          return {
            items: store.getItems() || [],
          };
        },
      },
    ];
  });
  
  export default ConnectedFeedsTab;
  