// @flow
import * as React from 'react';
import { buildURI, SORT_OPTIONS } from 'lbry-redux';
import { FormField } from 'component/common/form';
import FileCard from 'component/fileCard';
import type { FileInfo } from 'types/file_info';

type Props = {
  hideFilter: boolean,
  sortByHeight?: boolean,
  claimsById: Array<{}>,
  fileInfos: Array<FileInfo>,
  sortBy: string,
  page?: string,
  setFileListSort: (?string, string) => void,
};

class FileList extends React.PureComponent<Props> {
  static defaultProps = {
    hideFilter: false,
    sortBy: SORT_OPTIONS.DATE_NEW,
  };

  constructor(props: Props) {
    super(props);
    (this: any).handleSortChanged = this.handleSortChanged.bind(this);

    this.sortFunctions = {
      [SORT_OPTIONS.DATE_NEW]: fileInfos =>
        this.props.sortByHeight
          ? fileInfos.sort((fileInfo1, fileInfo2) => {
              if (fileInfo1.confirmations < 1) {
                return -1;
              } else if (fileInfo2.confirmations < 1) {
                return 1;
              }

              const height1 = this.props.claimsById[fileInfo1.claim_id]
                ? this.props.claimsById[fileInfo1.claim_id].height
                : 0;
              const height2 = this.props.claimsById[fileInfo2.claim_id]
                ? this.props.claimsById[fileInfo2.claim_id].height
                : 0;

              if (height1 !== height2) {
                // flipped because heigher block height is newer
                return height2 - height1;
              }

              if (fileInfo1.absolute_channel_position && fileInfo2.absolute_channel_position) {
                return fileInfo1.absolute_channel_position - fileInfo2.absolute_channel_position;
              }

              return 0;
            })
          : [...fileInfos].reverse(),
      [SORT_OPTIONS.DATE_OLD]: fileInfos =>
        this.props.sortByHeight
          ? fileInfos.slice().sort((fileInfo1, fileInfo2) => {
              const height1 = this.props.claimsById[fileInfo1.claim_id]
                ? this.props.claimsById[fileInfo1.claim_id].height
                : 999999;
              const height2 = this.props.claimsById[fileInfo2.claim_id]
                ? this.props.claimsById[fileInfo2.claim_id].height
                : 999999;
              if (height1 < height2) {
                return -1;
              } else if (height1 > height2) {
                return 1;
              }
              return 0;
            })
          : fileInfos,
      [SORT_OPTIONS.TITLE]: fileInfos =>
        fileInfos.slice().sort((fileInfo1, fileInfo2) => {
          const getFileTitle = fileInfo => {
            const { value, metadata, name, claim_name: claimName } = fileInfo;
            if (metadata) {
              // downloaded claim
              return metadata.title || claimName;
            } else if (value) {
              // published claim
              const { title } = value.stream.metadata;
              return title || name;
            }
            // Invalid claim
            return '';
          };
          const title1 = getFileTitle(fileInfo1).toLowerCase();
          const title2 = getFileTitle(fileInfo2).toLowerCase();
          if (title1 < title2) {
            return -1;
          } else if (title1 > title2) {
            return 1;
          }
          return 0;
        }),
      [SORT_OPTIONS.FILENAME]: fileInfos =>
        fileInfos.slice().sort(({ file_name: fileName1 }, { file_name: fileName2 }) => {
          const fileName1Lower = fileName1.toLowerCase();
          const fileName2Lower = fileName2.toLowerCase();
          if (fileName1Lower < fileName2Lower) {
            return -1;
          } else if (fileName2Lower > fileName1Lower) {
            return 1;
          }
          return 0;
        }),
    };
  }

  getChannelSignature = (fileInfo: FileInfo) => {
    if (fileInfo.pending) {
      return undefined;
    }

    if (fileInfo.value) {
      return fileInfo.value.publisherSignature.certificateId;
    }
    return fileInfo.channel_claim_id;
  };

  handleSortChanged(event: SyntheticInputEvent<*>) {
    this.props.setFileListSort(this.props.page, event.target.value);
  }

  sortFunctions: {};

  render() {
    const { fileInfos, hideFilter, sortBy } = this.props;

    const content = [];
    if (!fileInfos) {
      return null;
    }

    this.sortFunctions[sortBy](fileInfos).forEach(fileInfo => {
      const {
        name: claimName,
        claim_name: claimNameDownloaded,
        claim_id: claimId,
        txid,
        nout,
        isNew,
      } = fileInfo;
      const uriParams = {};

      // This is unfortunate
      // https://github.com/lbryio/lbry/issues/1159
      const name = claimName || claimNameDownloaded;
      uriParams.contentName = name;
      uriParams.claimId = claimId;
      const uri = buildURI(uriParams);
      const outpoint = `${txid}:${nout}`;

      // See https://github.com/lbryio/lbry-desktop/issues/1327 for discussion around using outpoint as the key
      content.push(<FileCard key={outpoint} uri={uri} isNew={isNew} />);
    });

    return (
      <section>
        {!hideFilter && (
          <div className="file-list__sort">
            <FormField
              prefix={__('Sort by')}
              affixClass="form-field--align-center"
              type="select"
              value={sortBy}
              onChange={this.handleSortChanged}
            >
              <option value={SORT_OPTIONS.DATE_NEW}>{__('Newest First')}</option>
              <option value={SORT_OPTIONS.DATE_OLD}>{__('Oldest First')}</option>
              <option value={SORT_OPTIONS.TITLE}>{__('Title')}</option>
            </FormField>
          </div>
        )}
        <div className="card__list card__content">{content}</div>
      </section>
    );
  }
}

export default FileList;
