import {
  forwardRef,
  useCallback,
  useEffect,
  useImperativeHandle,
  useRef,
  useState,
} from "react";
import { Amap, Marker } from "@amap/amap-react";
import { AutoComplete, Button, Input, Space, message } from "antd";
import { debounce, isNumber } from "lodash";
import {
  AMapGeocoderGetAddressResult,
  DageMapMethods,
  DageMapPoisType,
  DageMapProps,
} from "./types";
import { DageMapGeocoder } from "./plugins";
import { getAmapInputTips } from "./utils";

export const DageMap = forwardRef<DageMapMethods, DageMapProps>(
  (
    {
      latitude,
      longitude,
      disabled,
      address,
      city,
      onlyCityArea,
      inputTipsApi,
      outCityAreaMessage,
      onAddressChange,
      onLngLatChange,
      onMapComplete,
      onError,
    },
    ref
  ) => {
    const mapRef = useRef<AMap.Map_2>();
    /** 是否禁用坐标解析地址 */
    const geocoderDisabled = useRef(false);
    const [loaded, setLoaded] = useState(false);
    /** 上一个坐标地址 */
    const prevPosition = useRef([longitude, latitude]);
    /** 输入框经度 */
    const [lng, setLng] = useState<number>(longitude);
    /** 输入框纬度 */
    const [lat, setLat] = useState<number>(latitude);
    const [options, setOptions] = useState<DageMapPoisType[]>([]);
    const [position, setPosition] = useState([longitude, latitude]);

    useImperativeHandle(ref, () => ({
      mapRef: mapRef.current,
    }));

    useEffect(() => {
      if (longitude === lng && latitude === lat) return;

      // 外部改动经纬度，不需要解析地址
      geocoderDisabled.current = true;
      setPosition([longitude, latitude]);
      setLat(latitude);
      setLng(longitude);
      prevPosition.current = [longitude, latitude];
    }, [longitude, latitude]);

    const handleSearch = useCallback(
      debounce(async (value: string) => {
        if (!value) {
          setOptions([]);
          return;
        }

        const { tips } = await getAmapInputTips(inputTipsApi, value, city);
        setOptions(tips || []);
      }, 500),
      [city]
    );

    const handleClick = useCallback(
      (e: AMap.Map_2, data: any) => {
        if (disabled) return;

        const { lng, lat } = data.lnglat;

        geocoderDisabled.current = false;

        setLat(lat);
        setLng(lng);
        setPosition([lng, lat]);
        onLngLatChange?.({
          lat,
          lng,
        });
      },
      [disabled, onLngLatChange]
    );

    /**
     * 地图初始化完成
     */
    const handleComplete = useCallback(() => {
      setLoaded(true);
      mapRef.current?.setCenter([longitude, latitude], false, 1000);
      onMapComplete?.();
    }, [longitude, latitude, onMapComplete]);

    const handleMarker = useCallback(
      debounce((e: any) => {
        const [lng, lat] = e._position;
        geocoderDisabled.current = false;
        setLat(lat);
        setLng(lng);
        onLngLatChange?.({
          lat,
          lng,
        });
        setPosition(e._position);
      }, 200),
      [onLngLatChange]
    );

    const handlePosition = useCallback(
      (long = lng, lati = lat) => {
        if (!long || !lati) return;

        onLngLatChange?.({
          lat: lati,
          lng: long,
        });
        setPosition([long, lati]);

        mapRef.current?.setCenter([long, lati], false, 1000);
      },
      [lng, lat, onLngLatChange]
    );

    /**
     * 坐标搜索
     */
    const handleLngLatSearch = useCallback(() => {
      geocoderDisabled.current = false;
      handlePosition();
    }, [handlePosition]);

    const handleSelect = useCallback(
      (val: string, opts: DageMapPoisType) => {
        const [lng, lat] = opts.location.split(",").map((i) => Number(i));

        setLng(lng);
        setLat(lat);
        geocoderDisabled.current = true;

        handlePosition(lng, lat);

        onLngLatChange?.({
          lat,
          lng,
        });

        prevPosition.current = [lng, lat];
      },
      [handlePosition, onLngLatChange]
    );

    const handleAutoCompleteChange = useCallback(
      (val: string) => {
        onAddressChange?.(val);
      },
      [onAddressChange]
    );

    const handleGeocoderAddress = (res: AMapGeocoderGetAddressResult) => {
      if (geocoderDisabled.current) return;

      if (
        onlyCityArea &&
        isNumber(city) &&
        !res.regeocode.addressComponent.adcode.startsWith(
          city.toString().substring(0, 2)
        )
      ) {
        // 超出市区范围
        handleOutCityAreaError();
        return;
      }

      onAddressChange?.(res.regeocode.formattedAddress);
      prevPosition.current = [lng, lat];
    };

    const handleOutCityAreaError = () => {
      outCityAreaMessage && message.error(outCityAreaMessage, 2);
      onError?.();
      setTimeout(() => {
        setLat(prevPosition.current[1]);
        setLng(prevPosition.current[0]);
        handlePosition(prevPosition.current[0], prevPosition.current[1]);
      }, 2000);
    };

    return (
      <>
        <div>
          <AutoComplete
            allowClear
            disabled={disabled}
            value={address}
            style={{ width: 450 }}
            options={options.map((i) => ({
              ...i,
              value: i.name,
            }))}
            onSearch={handleSearch}
            onSelect={handleSelect}
            onChange={handleAutoCompleteChange}
          >
            <Input allowClear placeholder="请输入详细描述" />
          </AutoComplete>
        </div>

        <Space style={{ margin: "15px 0" }}>
          <Input
            readOnly={disabled}
            value={lng}
            type="number"
            placeholder="请输入经度"
            onChange={(e) => setLng(Number(e.target.value))}
          />
          <Input
            readOnly={disabled}
            value={lat}
            type="number"
            placeholder="请输入纬度"
            onChange={(e) => setLat(Number(e.target.value))}
          />
          {!disabled && (
            <Button type="primary" onClick={handleLngLatSearch}>
              查询
            </Button>
          )}
        </Space>

        <div style={{ width: 650, height: 400 }}>
          <Amap
            ref={mapRef}
            zoom={17}
            onComplete={handleComplete}
            onClick={handleClick}
          >
            {loaded && position ? (
              <>
                <Marker
                  position={position}
                  draggable={!disabled}
                  onDragging={handleMarker}
                />

                {!disabled && (
                  <DageMapGeocoder
                    city={city}
                    position={position}
                    onChange={handleGeocoderAddress}
                    onError={handleOutCityAreaError}
                  />
                )}
              </>
            ) : (
              <></>
            )}
          </Amap>
        </div>
      </>
    );
  }
);

export * from "./types";
export * from "./utils";
