import { BaseEventOrig, InputProps, ScrollView } from '@tarojs/components';
import Taro, { useLoad } from '@tarojs/taro';

import { Search } from '@taroify/core';
import { useCallback, useEffect, useRef, useState } from 'react';

import { EventName, OpenSource } from '@/constants/app';
import { CITY_CODE_TO_NAME_MAP, CITY_INDEXES_LIST } from '@/constants/city';
import { logWithPrefix } from '@/utils/common';
import { getPageQuery, navigateBack } from '@/utils/route';

import './index.less';

interface Item {
  cityCode: number | string;
  cityName: string;
  keyword: string;
}

const PREFIX = 'search-city';
const HOT_CITY = [
  { cityCode: 110100, cityName: '北京' },
  { cityCode: 310100, cityName: '上海' },
  { cityCode: 440100, cityName: '广州' },
  { cityCode: 440300, cityName: '深圳' },
  { cityCode: 330100, cityName: '杭州' },
  { cityCode: 430100, cityName: '长沙' },
  { cityCode: 420100, cityName: '武汉' },
  { cityCode: 350200, cityName: '厦门' },
  { cityCode: 610100, cityName: '西安' },
  { cityCode: 410100, cityName: '郑州' },
  { cityCode: 510100, cityName: '成都' },
  { cityCode: 340100, cityName: '合肥' },
];
const OFFSET_INDEX_SIZE = 2;
const log = logWithPrefix(PREFIX);

const useHeight = () => {
  const [winHeight, setWinHeight] = useState(0);
  const [indexItemHeight, setIndexItemHeight] = useState(0);

  useEffect(() => {
    const windowInfo = Taro.getWindowInfo();
    const windowHeight = windowInfo.windowHeight;
    setWinHeight(windowHeight);
    // 上下预留两个选项高度的空白
    setIndexItemHeight(Math.floor(windowHeight / (26 + OFFSET_INDEX_SIZE * 2)));
  }, []);

  return [winHeight, indexItemHeight];
};

export default function SearchCity() {
  const [winHeight, indexItemHeight] = useHeight();
  const [currentCity, setCurrentCity] = useState<string>('');
  const [touchAnchor, setTouchAnchor] = useState<string | undefined>();
  const [touchMoving, setTouchMoving] = useState(false);
  const [searchResult, setSearchResult] = useState<Item[]>([]);
  const openSourceRef = useRef<OpenSource>(OpenSource.None);
  const showSearchList = searchResult.length > 0;

  const handleSearchChange = useCallback((event: BaseEventOrig<InputProps.inputEventDetail>) => {
    const value = event.detail.value;
    log('handleSearchChange', value);
    if (!value) {
      setSearchResult([]);
      return;
    }
    const result: Item[] = [];
    CITY_INDEXES_LIST.forEach(obj => {
      obj.data.forEach(city => {
        if (city.keyword.includes(value.toLocaleUpperCase())) {
          result.push({ ...city });
        }
      });
    });
    setSearchResult(result);
  }, []);

  const handleSelectCity = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
    const cityCode = e.currentTarget.dataset.code;
    Taro.eventCenter.trigger(EventName.SELECT_CITY, { openSource: openSourceRef.current, cityCode: String(cityCode) });
    navigateBack(1);
  }, []);

  const handleTouchStart = useCallback(
    (e: React.TouchEvent<HTMLDivElement>) => {
      const pageY = e.touches[0].pageY;
      const index = Math.floor(pageY / indexItemHeight) - OFFSET_INDEX_SIZE;
      if (index < 0 || index >= CITY_INDEXES_LIST.length) {
        return;
      }
      const item = CITY_INDEXES_LIST[index];
      if (item) {
        setTouchMoving(true);
        setTouchAnchor(item.letter);
      }
    },
    [indexItemHeight]
  );

  const handleTouchMove = useCallback(
    (e: React.TouchEvent<HTMLDivElement>) => {
      const pageY = e.touches[0].pageY;
      const index = Math.floor(pageY / indexItemHeight) - OFFSET_INDEX_SIZE;
      if (index < 0 || index >= CITY_INDEXES_LIST.length) {
        return;
      }
      const item = CITY_INDEXES_LIST[index];
      item && setTouchAnchor(item.letter);
    },
    [indexItemHeight]
  );

  const handleTouchEnd = useCallback((e: React.TouchEvent<HTMLDivElement>) => {
    e.stopPropagation();
    setTouchMoving(false);
    log('touch end');
  }, []);

  const handleClickAnchor = useCallback((anchor: string) => {
    setTouchAnchor(anchor);
    log('click anchor', anchor);
  }, []);

  useLoad(() => {
    const query = getPageQuery<{ city: string; source: OpenSource }>();
    log('query', query);
    const { city: cityCode, source: openSource } = query;
    if (!cityCode) {
      return;
    }
    setCurrentCity(cityCode);
    openSourceRef.current = openSource || OpenSource.None;
  });

  return (
    <div className={PREFIX}>
      <ScrollView scrollY style={{ height: winHeight }} scrollIntoView={touchAnchor}>
        <Search
          className={`${PREFIX}__search`}
          placeholder="输入城市名称"
          shape="rounded"
          onChange={handleSearchChange}
        />
        {showSearchList && (
          <div className={`${PREFIX}__search-list`}>
            {searchResult.map(city => (
              <div
                key={city.cityCode}
                className={`${PREFIX}__indexes-cell`}
                data-code={city.cityCode}
                onClick={handleSelectCity}
              >
                {city.cityName}
              </div>
            ))}
          </div>
        )}
        {!showSearchList && (
          <div>
            <div className={`${PREFIX}__position-title`}>当前城市</div>
            <div className={`${PREFIX}__position-city`}>{CITY_CODE_TO_NAME_MAP.get(currentCity)}</div>
            <div className={`${PREFIX}__hot-city-title`}>热门城市</div>
            <div className={`${PREFIX}__hot-city-container`}>
              {HOT_CITY.map(city => (
                <div
                  key={city.cityCode}
                  className={`${PREFIX}__hot-city-item`}
                  data-code={city.cityCode}
                  onClick={handleSelectCity}
                >
                  {city.cityName}
                </div>
              ))}
            </div>
            <div className={`${PREFIX}__indexes-list`}>
              {CITY_INDEXES_LIST.map(item => {
                return (
                  <div key={item.letter} className={`${PREFIX}__indexes-fragment`}>
                    <div className={`${PREFIX}__indexes-anchor`} id={item.letter}>
                      {item.letter}
                    </div>
                    {item.data.map(city => (
                      <div
                        key={city.cityCode}
                        className={`${PREFIX}__indexes-cell`}
                        data-code={city.cityCode}
                        onClick={handleSelectCity}
                      >
                        {city.cityName}
                      </div>
                    ))}
                  </div>
                );
              })}
            </div>
          </div>
        )}
      </ScrollView>
      <div>
        {!showSearchList && (
          <div
            className={`${PREFIX}__indexes-bar`}
            onTouchStart={handleTouchStart}
            onTouchMove={handleTouchMove}
            onTouchEnd={handleTouchEnd}
            onTouchCancel={handleTouchEnd}
            style={{ top: indexItemHeight * OFFSET_INDEX_SIZE }}
          >
            {CITY_INDEXES_LIST.map(item => {
              return (
                <div
                  key={item.letter}
                  className={`${PREFIX}__indexes-bar-item`}
                  style={{ height: indexItemHeight }}
                  onClick={() => handleClickAnchor(item.letter)}
                >
                  {item.letter}
                </div>
              );
            })}
          </div>
        )}
        {touchAnchor && touchMoving && <div className={`${PREFIX}__indexes-index-alert`}>{touchAnchor}</div>}
      </div>
    </div>
  );
}
