import * as qs from 'qs';
import moment from 'moment';
import { API, AMapQuery } from './api';
import { adapterAddressComponent, adapterDistrict, adapterTips } from './adapter';

interface IWindow {
  fetch<T>(input: RequestInfo, init?: RequestInit): Promise<IApiResponse<T>>;
}

export default class Service {
  constructor(private fetch: IWindow['fetch']) {}

  /**
   * 获取房源列表
   *
   * @param {HouseListParams} [body={}]
   * @returns {Promise<IApiListResponse<IHouseDetail>>}
   * @memberof Service
   */
  public fetchHouseList(body: HouseListParams = {}): Promise<IApiListResponse<IHouseDetail>> {
    const defaultResponse: IApiListResponse<IHouseDetail> = {
      current: 0,
      hasNextPage: false,
      list: [],
      pages: 0,
      size: 0,
      total: 0,
    };

    const queryData = { ...body };
    if (body.beginDate) {
      queryData.beginDate = moment(body.beginDate).format('YYYY-MM-DD');
    }

    if (body.endDate) {
      queryData.endDate = moment(body.endDate).format('YYYY-MM-DD');
    }

    if (!body.limitImage) {
      queryData.limitImage = 5;
    }

    if (!body.pageSize) {
      queryData.pageSize = 10;
    }

    // 如果没有排序并且不是按位置搜索, 默认推荐排序
    const sortKeys = ['rankingSort', 'starsSort', 'priceSort'];
    if (!sortKeys.some(key => Reflect.has(queryData, key)) && !queryData.latitude) {
      queryData.rankingSort = 0;
    }

    return this.fetch(API.SearchHouse + '?' + qs.stringify(queryData))
      .then(response => {
        if (!response || !response.data) {
          return defaultResponse;
        }
        return response.data as IApiListResponse<IHouseDetail>;
      })
      .catch(() => defaultResponse);
  }

  /**
   * 批量查找位置
   *
   * @param {string} keyword
   * @returns {Promise<IAmapTips[]>}
   * @memberof Service
   */
  // tslint:disable-next-line:prefer-array-literal
  public async batchSearchAddress(keywords: string): Promise<(IAmapTips | null)[]> {
    function ops(poiType: AMapQuery) {
      const querystring = qs.stringify({ datatype: 'poi', keywords, type: poiType });
      return {
        url: API.AmapOpsURL + querystring,
      };
    }

    try {
      const response = (await this.fetch(API.BathSearch, {
        body: JSON.stringify({ ops: [ops(AMapQuery.normalType), ops(AMapQuery.allType)] }),
        method: 'post',
      })) as any;

      const result = adapterTips(response as IAmapBatchResponse[]);

      const returnResult: (IAmapTips | null)[] = [];
      if (result[0]) {
        returnResult.push.apply(returnResult, result[0]
          .filter(v => !!v)
          .map(v => ({ ...v, istrative: true })) as IAmapTips[]);
      }

      returnResult.push.apply(returnResult, result[1]);
      return returnResult;
    } catch (error) {
      return [];
    }
  }

  /**
   * 地址逆装换
   *
   * @protected
   * @param {ILocationBaseParams} location
   * @returns {(Promise<IAddressComponent | null>)}
   * @memberof Service
   */
  public async georegeo(location: ILocationBaseParams): Promise<IAddressComponent | null> {
    try {
      const result = await this.fetch(`${API.regeo}&location=${location.longitude},${location.latitude}`);
      return adapterAddressComponent(result as IGeoregeoResponse);
    } catch (error) {
      return null;
    }
  }

  /**
   * 区域转坐标
   *
   * @param {*} keyword
   * @memberof Service
   */
  public async districtToCoordinates(keyword?: string): Promise<ILocationBaseParams | null> {
    if (!keyword) return null;
    try {
      const result = await this.fetch(`${API.AmapDistrict}&keywords=${keyword}`);
      const [coord] = adapterDistrict(result as IDistrictResponse);
      return coord;
    } catch (error) {
      return null;
    }
  }
}
