// @flow
import React, { useState } from 'react';
import { parseURI } from 'lbry-redux';
import Page from 'component/page';
import SubscribeButton from 'component/subscribeButton';
import BlockButton from 'component/blockButton';
import ShareButton from 'component/shareButton';
import { Tabs, TabList, Tab, TabPanels, TabPanel } from 'component/common/tabs';
import { withRouter } from 'react-router';
import Button from 'component/button';
import { formatLbryUrlForWeb } from 'util/url';
import ChannelContent from 'component/channelContent';
import ChannelAbout from 'component/channelAbout';
import ChannelDiscussion from 'component/channelDiscussion';
import ChannelThumbnail from 'component/channelThumbnail';
import ChannelEdit from 'component/channelEdit';
import ClaimUri from 'component/claimUri';
import * as ICONS from 'constants/icons';
import classnames from 'classnames';
import * as MODALS from 'constants/modal_types';
import { Form, FormField } from 'component/common/form';
import ClaimPreview from 'component/claimPreview';
import Icon from 'component/common/icon';
import HelpLink from 'component/common/help-link';
import debounce from 'util/debounce';
import { DEBOUNCE_WAIT_DURATION_MS } from 'constants/search';

const PAGE_VIEW_QUERY = `view`;
const ABOUT_PAGE = `about`;
const DISCUSSION_PAGE = `discussion`;
const LIGHTHOUSE_URL = 'https://lighthouse.lbry.com/search';

type Props = {
  uri: string,
  claim: ChannelClaim,
  title: ?string,
  cover: ?string,
  thumbnail: ?string,
  page: number,
  location: { search: string },
  history: { push: string => void },
  match: { params: { attribute: ?string } },
  channelIsMine: boolean,
  isSubscribed: boolean,
  channelIsBlocked: boolean,
  blackListedOutpoints: Array<{
    txid: string,
    nout: number,
  }>,
  openModal: (id: string, { uri: string, claimIsMine?: boolean, isSupport?: boolean }) => void,
  supportOption: boolean,
  fetchSubCount: string => void,
  subCount: number,
};

function ChannelPage(props: Props) {
  const {
    uri,
    title,
    cover,
    history,
    location,
    page,
    channelIsMine,
    thumbnail,
    claim,
    isSubscribed,
    channelIsBlocked,
    blackListedOutpoints,
    openModal,
    supportOption,
    fetchSubCount,
    subCount,
  } = props;

  const { channelName } = parseURI(uri);
  const { search } = location;
  const urlParams = new URLSearchParams(search);
  const currentView = urlParams.get(PAGE_VIEW_QUERY) || undefined;
  const { permanent_url: permanentUrl } = claim;
  const [editing, setEditing] = useState(false);
  const [thumbPreview, setThumbPreview] = useState(thumbnail);
  const [coverPreview, setCoverPreview] = useState(cover);
  const [searchQuery, setSearchQuery] = useState('');
  const [searchResults, setSearchResults] = useState(undefined);
  // passing callback to useState ensures it's only set on initial render. Without this, the debouncing wont work.
  const [performSearch] = useState(() => debounce(updateResults, DEBOUNCE_WAIT_DURATION_MS));
  const claimId = claim.claim_id;

  // If a user changes tabs, update the url so it stays on the same page if they refresh.
  // We don't want to use links here because we can't animate the tab change and using links
  // would alter the Tab label's role attribute, which should stay role="tab" to work with keyboards/screen readers.
  const tabIndex = currentView === ABOUT_PAGE || editing ? 1 : currentView === DISCUSSION_PAGE ? 2 : 0;

  function onTabChange(newTabIndex) {
    let url = formatLbryUrlForWeb(uri);
    let search = '?';

    if (newTabIndex === 0) {
      setSearchResults(null);
      search += `page=${page}`;
    } else if (newTabIndex === 1) {
      search += `${PAGE_VIEW_QUERY}=${ABOUT_PAGE}`;
    } else {
      search += `${PAGE_VIEW_QUERY}=${DISCUSSION_PAGE}`;
    }
    history.push(`${url}${search}`);
  }

  function handleSearch() {
    performSearch(searchQuery);
  }

  function updateResults(query) {
    // In order to display original search results, search results must be set to null. A query of '' should display original results.
    if (query === '') return setSearchResults(null);

    const url = generateFetchUrl(query);
    getResults(url);
  }

  function generateFetchUrl(query) {
    return `${LIGHTHOUSE_URL}?s=${encodeURIComponent(query)}&channel_id=${encodeURIComponent(claim.claim_id)}`;
  }

  function getResults(fetchUrl) {
    fetch(fetchUrl)
      .then(res => res.json())
      .then(results => {
        const urls = results.map(({ name, claimId }) => {
          return `lbry://${name}#${claimId}`;
        });
        setSearchResults(urls);
      })
      .catch(() => {
        setSearchResults(null);
      });
  }

  React.useEffect(() => {
    handleSearch();
  }, [searchQuery]);

  function handleInputChange(e) {
    const { value } = e.target;
    setSearchQuery(value);
  }

  let channelIsBlackListed = false;

  if (claim && blackListedOutpoints) {
    channelIsBlackListed = blackListedOutpoints.some(
      outpoint => outpoint.txid === claim.txid && outpoint.nout === claim.nout
    );
  }

  React.useEffect(() => {
    setSearchResults(null);
    setSearchQuery('');

    fetchSubCount(claimId);
  }, [uri, fetchSubCount, claimId]);

  return (
    <Page>
      <ClaimUri uri={uri} />

      <header className="channel-cover">
        <div className="channel__quick-actions">
          {!channelIsBlocked && !channelIsBlackListed && <ShareButton uri={uri} isChannel />}
          {!channelIsMine && (
            <Button
              button="alt"
              icon={ICONS.TIP}
              label={__('Tip')}
              title={__('Send a tip to this creator')}
              onClick={() => openModal(MODALS.SEND_TIP, { uri, channelIsMine, isSupport: false })}
            />
          )}
          {(channelIsMine || (!channelIsMine && supportOption)) && (
            <Button
              button="alt"
              icon={ICONS.SUPPORT}
              label={__('Support')}
              title={__('Support this creator')}
              onClick={() => openModal(MODALS.SEND_TIP, { uri, channelIsMine, isSupport: true })}
            />
          )}
          {!channelIsBlocked && (!channelIsBlackListed || isSubscribed) && <SubscribeButton uri={permanentUrl} />}
          {!isSubscribed && <BlockButton uri={permanentUrl} />}
        </div>
        {!editing && cover && (
          <img
            className={classnames('channel-cover__custom', { 'channel__image--blurred': channelIsBlocked })}
            src={cover}
          />
        )}
        {editing && <img className="channel-cover__custom" src={coverPreview} />}
        {/* component that offers select/upload */}
        <div className="channel__primary-info">
          {!editing && (
            <ChannelThumbnail className="channel__thumbnail--channel-page" uri={uri} obscure={channelIsBlocked} />
          )}
          {editing && (
            <ChannelThumbnail className="channel__thumbnail--channel-page" uri={uri} thumbnailPreview={thumbPreview} />
          )}
          <h1 className="channel__title">{title || '@' + channelName}</h1>
          {channelIsMine && !editing && (
            <Button button="alt" title={__('Edit')} onClick={() => setEditing(!editing)} icon={ICONS.EDIT} />
          )}
          <div className="channel__meta">
            <span>
              {subCount} {subCount !== 1 ? __('Followers') : __('Follower')}
              <HelpLink href="https://lbry.com/faq/views" />
            </span>
          </div>
        </div>
      </header>
      <Tabs onChange={onTabChange} index={tabIndex}>
        <TabList className="tabs__list--channel-page">
          <Tab disabled={editing}>{__('Content')}</Tab>
          <Tab>{editing ? __('Editing Your Channel') : __('About')}</Tab>
          <Tab disabled={editing}>{__('Comments')}</Tab>
          {/* only render searchbar on content page (tab index 0 === content page) */}
          {tabIndex === 0 ? (
            <Form onSubmit={handleSearch} className="wunderbar--inline">
              <Icon icon={ICONS.SEARCH} />
              <FormField
                className="wunderbar__input"
                value={searchQuery}
                onChange={handleInputChange}
                type="text"
                placeholder={__('Search')}
              />
            </Form>
          ) : (
            <div />
          )}
        </TabList>

        <TabPanels>
          <TabPanel>
            {searchResults ? (
              searchResults.map(url => <ClaimPreview key={url} uri={url} />)
            ) : (
              <ChannelContent uri={uri} channelIsBlackListed={channelIsBlackListed} />
            )}
          </TabPanel>
          <TabPanel>
            {editing ? (
              <ChannelEdit
                uri={uri}
                setEditing={setEditing}
                updateThumb={v => setThumbPreview(v)}
                updateCover={v => setCoverPreview(v)}
              />
            ) : (
              <ChannelAbout uri={uri} />
            )}
          </TabPanel>
          <TabPanel>
            <ChannelDiscussion uri={uri} />
          </TabPanel>
        </TabPanels>
      </Tabs>
    </Page>
  );
}

export default withRouter(ChannelPage);
