import * as React from 'react';
import { useRecoilState } from 'recoil';
import { DelayMapping, ProxiesMapping, ProxyItem } from 'src/store/types';

import {
  // types
  NonProxyTypes,
  // atom
  proxyFilterText,
} from '../../store/proxies';

const { useMemo } = React;

function filterAvailableProxies(list: string[], delay: DelayMapping) {
  return list.filter((name) => {
    const d = delay[name];
    if (d === undefined) {
      return true;
    }
    if (d.number === 0) {
      return false;
    } else {
      return true;
    }
  });
}

const getSortDelay = (
  d:
    | undefined
    | {
        number?: number;
      },
  proxyInfo: ProxyItem
) => {
  if (d && typeof d.number === 'number' && d.number > 0) {
    return d.number;
  }

  const type = proxyInfo && proxyInfo.type;
  if (type && NonProxyTypes.indexOf(type) > -1) return -1;

  return 999999;
};

const ProxySortingFns = {
  Natural: (proxies: string[]) => proxies,
  LatencyAsc: (
    proxies: string[],
    delay: DelayMapping,
    proxyMapping?: ProxiesMapping
  ) => {
    return proxies.sort((a, b) => {
      const d1 = getSortDelay(delay[a], proxyMapping && proxyMapping[a]);
      const d2 = getSortDelay(delay[b], proxyMapping && proxyMapping[b]);
      return d1 - d2;
    });
  },
  LatencyDesc: (
    proxies: string[],
    delay: DelayMapping,
    proxyMapping?: ProxiesMapping
  ) => {
    return proxies.sort((a, b) => {
      const d1 = getSortDelay(delay[a], proxyMapping && proxyMapping[a]);
      const d2 = getSortDelay(delay[b], proxyMapping && proxyMapping[b]);
      return d2 - d1;
    });
  },
  NameAsc: (proxies: string[]) => {
    return proxies.sort();
  },
  NameDesc: (proxies: string[]) => {
    return proxies.sort((a, b) => {
      if (a > b) return -1;
      if (a < b) return 1;
      return 0;
    });
  },
};

function filterStrArr(all: string[], searchText: string) {
  const segments = searchText
    .toLowerCase()
    .split(' ')
    .map((x) => x.trim())
    .filter((x) => !!x);

  if (segments.length === 0) return all;

  return all.filter((name) => {
    let i = 0;
    for (; i < segments.length; i++) {
      const seg = segments[i];
      if (name.toLowerCase().indexOf(seg) > -1) return true;
    }
    return false;
  });
}

function filterAvailableProxiesAndSort(
  all: string[],
  delay: DelayMapping,
  hideUnavailableProxies: boolean,
  filterText: string,
  proxySortBy: string,
  proxies?: ProxiesMapping
) {
  // all is freezed
  let filtered = [...all];
  if (hideUnavailableProxies) {
    filtered = filterAvailableProxies(all, delay);
  }

  if (typeof filterText === 'string' && filterText !== '') {
    filtered = filterStrArr(filtered, filterText);
  }
  return ProxySortingFns[proxySortBy](filtered, delay, proxies);
}

export function useFilteredAndSorted(
  all: string[],
  delay: DelayMapping,
  hideUnavailableProxies: boolean,
  proxySortBy: string,
  proxies?: ProxiesMapping
) {
  const [filterText] = useRecoilState(proxyFilterText);
  return useMemo(
    () =>
      filterAvailableProxiesAndSort(
        all,
        delay,
        hideUnavailableProxies,
        filterText,
        proxySortBy,
        proxies
      ),
    [all, delay, hideUnavailableProxies, filterText, proxySortBy, proxies]
  );
}
