import React, { useState, useMemo, useCallback } from "react";
import { useTranslation } from 'react-i18next';
import { Link, useRouteMatch, useParams, generatePath, useHistory } from "react-router-dom";
import Icon from './Icon';
import { Summary, statusMapper, statusSum, StatusList } from './Status';
import { ParsedMirror } from "../schema";
import { groupBy } from "./utils";

const Group = React.memo((
  { group, entries, filtered, defaultCollapse = true }:
    { group: string, entries: ParsedMirror[], filtered: boolean, defaultCollapse?: boolean }) => {
  const match = useRouteMatch();
  const [collapse, setCollapse] = useState(defaultCollapse);
  const toggleCollapse = useCallback(() => setCollapse(c => !c), []);

  const summary = useMemo(() =>
    <Summary sum={statusSum(entries.map(({ status }) => statusMapper(status)))} />,
    [entries]);

  return (
    <div className={"group" + (filtered ? " filtered" : "") + (collapse ? "" : " group-expanded")}>
      <Link to={generatePath(match.path, { filter: encodeURIComponent(group) })}>
        <div className="group-header" id={group} onClick={toggleCollapse}>
          <h2 className="heading">
            {collapse ?
              (<Icon>add</Icon>) :
              (<Icon>remove</Icon>)
            }
            {group}
          </h2>
          <div>
            {summary}
          </div>
        </div>
      </Link>
      <div className="group-items">
        {collapse == false && entries.sort((a, b) => a.source.localeCompare(b.source)).map(({ full, help, upstream, desc, status, source, size, note }, idx) => (
          <div key={idx}>
            <h3>
              <a href={full} target="_blank">
                {source}
              </a>
              {help && (
                <a className="help" href={help} target="_blank">
                  <Icon title="Help">help</Icon>
                </a>
              )}
            </h3>
            {upstream && (
              <div className="upstream">
                <Icon>outbound</Icon>
                {upstream}
              </div>
            )}
            {status && (
              <StatusList mapper={statusMapper(status)} />
            )}
            {size && (
              <div className="size">
                <Icon>save</Icon>
                {size}
              </div>
            )}
            {note && (
              <div className="note">
                <Icon>note</Icon>
                {note}
              </div>
            )}
            {desc && (
              <div className="desc">{desc}</div>
            )}
          </div>
        ))}
      </div>
    </div>
  );
});

export default React.memo(({ mirrors }: { mirrors: ParsedMirror[] }) => {
  const { t, i18n } = useTranslation();
  const history = useHistory(), match = useRouteMatch(), params = useParams() as { filter?: string };
  const [filter, setFilter] = useState(params.filter ?? "");

  // Clustering
  const grouped = useMemo(() =>
    Object.entries(groupBy(mirrors, m => m.cname))
      .map(([k, v]) => ({ sortKey: k.toLowerCase(), group: k, entries: v }))
    , [mirrors]);

  const updateFilter = useCallback((ev) => setFilter(ev.target.value), []);
  const uploadFilter = useCallback((ev) => {
    if (ev.key === 'Enter')
      history.push(generatePath(match.path, { filter: ev.target.value }));
  }, []);

  const regex = useMemo(() => {
    let regex;
    try {
      if (filter === '')
        regex = null;
      else
        // user input may be invalid regex
        regex = new RegExp(filter, 'i');
    } catch (error) {
      regex = null;
    }
    if (regex !== null) console.log("valid regex:", regex);
    return regex;
  }, [filter]);
  const begin = performance.now();
  const filtered = grouped
    .map((e) => {
      let m = null;
      let filtered = false;
      let index = 1e15;
      if (regex !== null) {
        m = regex.exec(e.group);
        filtered = m === null;
        if (!filtered)
          index = m!.index;
      }
      return { ...e, filtered, index, defaultCollapse: filter !== e.group };
    })
    .sort((a, b) => {
      if (a.index == b.index)
        return a.sortKey.localeCompare(b.sortKey);
      return a.index - b.index;
    });
  const end = performance.now();
  //console.log(`Sort`, end - begin);

  return (
    <div className={"mirrorz"}>
      <div className="search">
        <input value={filter} onChange={updateFilter} onKeyDown={uploadFilter} placeholder={t("mirrors_prompt")} />
        <Icon>search</Icon>
      </div>

      <div className="mirrors">
        {filtered.map(({ group, entries, filtered, defaultCollapse }) => (
          <Group key={group} filtered={filtered} group={group} entries={entries} defaultCollapse={defaultCollapse} />
        ))}
      </div>
    </div>
  );
});