import { Button } from '@tarojs/components';
import Taro, { NodesRef, useLoad } from '@tarojs/taro';

import { Tabs } from '@taroify/core';
import { ArrowDown, ArrowUp } from '@taroify/icons';
import classNames from 'classnames';
import { useCallback, useEffect, useRef, useState } from 'react';

import JobList from '@/components/job-list';
import JobPicker from '@/components/job-picker';
import Overlay from '@/components/overlay';
import SafeBottomPadding from '@/components/safe-bottom-padding';
import SearchInput from '@/components/search';
import { EventName, OpenSource, PageUrl } from '@/constants/app';
import { CacheKey } from '@/constants/cache-key';
import { CITY_CODE_TO_NAME_MAP } from '@/constants/city';
import { JOB_TABS, JobType, EmployType } from '@/constants/job';
import useListHeight, { IUseListHeightProps } from '@/hooks/use-list-height';
import { logWithPrefix } from '@/utils/common';
import { getPageQuery, navigateTo } from '@/utils/route';

import './index.less';

const PREFIX = 'page-search-job';
const LIST_CLASS = 'search-job-list-container';
const SAFE_PADDING_BOTTOM_CLASS = `${PREFIX}__safe-padding-bottom`;
const CALC_LIST_PROPS: IUseListHeightProps = {
  selectors: [`.${LIST_CLASS}`, `.${PREFIX}`, `.${SAFE_PADDING_BOTTOM_CLASS}`],
  calc: (
    rects: [
      NodesRef.BoundingClientRectCallbackResult,
      NodesRef.BoundingClientRectCallbackResult,
      NodesRef.BoundingClientRectCallbackResult,
    ]
  ) => {
    const [listRect, pageRect, safePaddingRect] = rects;
    return pageRect.bottom - listRect.top - safePaddingRect.height;
  },
};
const log = logWithPrefix(PREFIX);

export default function JobSearch() {
  const listHeight = useListHeight(CALC_LIST_PROPS);
  const [focus, setFocus] = useState(true);
  const [employType, setEmployType] = useState(EmployType.All);
  const [tabType, setTabType] = useState<JobType>(JobType.All);
  const [value, setValue] = useState<string>('');
  const [keyWord, setKeyWord] = useState<string>('');
  const [cityCode, setCityCode] = useState<string>('');
  const [showMenu, setShowMenu] = useState<boolean>(false);
  const historyRef = useRef<string[]>([]);
  const showContent = keyWord.length > 0;

  const handleUpdateHistory = useCallback((historyKeyword: string) => {
    const newHistory = [...new Set([historyKeyword, ...historyRef.current])].slice(0, 20);
    historyRef.current = newHistory;
    Taro.setStorageSync(CacheKey.JOB_SEARCH_HISTORY, newHistory);
    log('handleUpdateHistory', newHistory);
  }, []);

  const handleClickHistoryItem = useCallback(
    (historyKeyword: string) => {
      setValue(historyKeyword);
      setKeyWord(historyKeyword);
      handleUpdateHistory(historyKeyword);
    },
    [handleUpdateHistory]
  );

  const handleClickSearch = useCallback(() => {
    if (value === keyWord) {
      return;
    }
    setFocus(false);
    setKeyWord(value);
    handleUpdateHistory(value);
  }, [value, keyWord, handleUpdateHistory]);

  const handleSearchClear = useCallback(() => {
    setValue('');
    setKeyWord('');
  }, []);

  const handleSearchBlur = useCallback(() => setFocus(false), []);

  const handleSearchFocus = useCallback(() => setFocus(true), []);

  const handleSearchChange = useCallback(e => setValue(e.detail.value), []);

  const handleClickCityMenu = useCallback(() => {
    navigateTo(PageUrl.CitySearch, { city: cityCode, source: OpenSource.JobSearch });
  }, [cityCode]);

  const handleClickTypeMenu = useCallback(() => {
    setShowMenu(!showMenu);
  }, [showMenu]);

  const handleHideMenu = useCallback(() => setShowMenu(false), []);

  const handleCityChange = useCallback(data => {
    log('handleCityChange', data);
    const { openSource, cityCode: code } = data;
    if (openSource !== OpenSource.JobSearch) {
      return;
    }
    setCityCode(code);
  }, []);

  const handleTypePickerConfirm = useCallback((newEmployType: EmployType) => {
    log('picker confirm', newEmployType);
    setEmployType(newEmployType);
    setShowMenu(false);
  }, []);

  const onTypeChange = useCallback(type => setTabType(type), [setTabType]);

  useLoad(() => {
    const query = getPageQuery<{ city: string }>();
    const currentCity = query.city;
    if (!currentCity) {
      return;
    }
    setCityCode(currentCity);
  });

  useLoad(() => {
    const cacheHistory = Taro.getStorageSync(CacheKey.JOB_SEARCH_HISTORY);
    log('useLoad', cacheHistory);
    if (!cacheHistory) {
      return;
    }
    historyRef.current = cacheHistory;
  });

  useEffect(() => {
    Taro.eventCenter.on(EventName.SELECT_CITY, handleCityChange);
    return () => {
      Taro.eventCenter.off(EventName.SELECT_CITY, handleCityChange);
    };
  }, [handleCityChange]);

  const searchAction = (
    <Button className={`${PREFIX}__search-button`} hoverClass="none" onClick={handleClickSearch}>
      搜索
    </Button>
  );

  return (
    <div className={PREFIX}>
      <SearchInput
        focus={focus}
        value={value}
        placeholder="你想搜什么"
        searchAction={searchAction}
        className={`${PREFIX}__search`}
        onClear={handleSearchClear}
        onBlur={handleSearchBlur}
        onFocus={handleSearchFocus}
        onSearch={handleClickSearch}
        onChange={handleSearchChange}
      />
      <div className={`${PREFIX}__page-content`} style={{ visibility: showContent ? 'visible' : 'hidden' }}>
        <div className={`${PREFIX}__search-filter`}>
          <div className={classNames(`${PREFIX}__search-filter-menu`)} onClick={handleClickCityMenu}>
            <div className="title">{CITY_CODE_TO_NAME_MAP.get(cityCode)}</div>
            <ArrowDown />
          </div>
          <div
            className={classNames(`${PREFIX}__search-filter-menu`, { show: showMenu })}
            onClick={handleClickTypeMenu}
          >
            <div className="title">筛选</div>
            {showMenu ? <ArrowUp /> : <ArrowDown />}
          </div>
        </div>
        <Overlay
          visible={showMenu}
          onClickOuter={handleHideMenu}
          outerClassName={`${PREFIX}__overlay-outer`}
          innerClassName={`${PREFIX}__overlay-inner`}
        >
          <JobPicker onConfirm={handleTypePickerConfirm} />
        </Overlay>
        <Tabs className={`${PREFIX}__type-tabs`} value={tabType} onChange={onTypeChange}>
          {JOB_TABS.map(tab => (
            <Tabs.TabPane title={tab.title} key={tab.type} value={tab.type}>
              <JobList
                cityCode={cityCode}
                category={tab.type}
                employType={employType}
                keyWord={keyWord}
                visible={tabType === tab.type}
                className={LIST_CLASS}
                listHeight={listHeight}
              />
            </Tabs.TabPane>
          ))}
        </Tabs>
      </div>
      <div className={`${PREFIX}__search-history`} style={{ visibility: showContent ? 'hidden' : 'visible' }}>
        <div className={`${PREFIX}__search-history-title`}>历史搜索</div>
        <div className={`${PREFIX}__search-history-items`}>
          {historyRef.current.map(historyKeyword => (
            <div
              key={historyKeyword}
              className={`${PREFIX}__search-history-item`}
              onClick={() => handleClickHistoryItem(historyKeyword)}
            >
              {historyKeyword}
            </div>
          ))}
        </div>
      </div>
      <SafeBottomPadding className={SAFE_PADDING_BOTTOM_CLASS} />
    </div>
  );
}
