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

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

import { CITY_CODE_TO_NAME_MAP, CITY_INDEXES_LIST, GROUP_CITY_INDEXES_LIST } from '@/constants/city';
import { logWithPrefix } from '@/utils/common';

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 realtimeLogger = Taro.getRealtimeLogManager();
realtimeLogger.tag(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 interface SearchCityProps {
  onSelectCity: (cityCode: string) => void;
  currentCity?: string;
  forGroup?: boolean;
  banner?: string;
  offset?: number;
}

export default function SearchCity({
  onSelectCity,
  currentCity = '',
  banner = '',
  forGroup = false,
  offset = 0,
}: SearchCityProps) {
  const [winHeight, indexItemHeight] = useHeight();
  const [touchAnchor, setTouchAnchor] = useState<string | undefined>();
  const [touchMoving, setTouchMoving] = useState(false);
  const [searchResult, setSearchResult] = useState<Item[]>([]);
  const showSearchList = searchResult.length > 0;
  const CITY_LIST = forGroup ? GROUP_CITY_INDEXES_LIST : CITY_INDEXES_LIST;

  const handleSearchChange = useCallback((event: BaseEventOrig<InputProps.inputEventDetail>) => {
    const value = event.detail.value;
    log('handleSearchChange', value);
    if (!value) {
      setSearchResult([]);
      return;
    }
    const result: Item[] = [];
    CITY_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;
      onSelectCity(String(cityCode));
    },
    [onSelectCity]
  );

  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_LIST.length) {
        return;
      }
      const item = CITY_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_LIST.length) {
        return;
      }
      const item = CITY_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);
  }, []);

  return (
    <div className={PREFIX}>
      <ScrollView scrollY style={{ height: winHeight - offset }} scrollIntoView={touchAnchor}>
        <div className={`${PREFIX}__search-wrapper ${forGroup ? 'group' : ''}`}>
          {forGroup && banner ? (
            <div className={`${PREFIX}__banner`}>
              <div className="dash"></div>
              <div className="text">{banner}</div>
              <div className="dash"></div>
            </div>
          ) : null}
          <Search
            className={`${PREFIX}__search`}
            placeholder="输入城市名称"
            shape="rounded"
            onChange={handleSearchChange}
          />
        </div>
        {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_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 + (forGroup ? 72 : 0) }}
          >
            {CITY_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>
  );
}
