import type { BasePlayer } from "../types";
import { useCallback, useEffect, useMemo, useState } from "react";
import { calculate, getRoundTable } from "../utils/common";
import { Button, Card, Divider, Flex, Table, Modal, Typography, Input } from "antd";
import styled from "styled-components";
import { cloneDeep } from "lodash";
import { ClearOutlined, EditOutlined, ShareAltOutlined } from "@ant-design/icons";
import { useLocation } from "react-router";
import { MATCH_RESULT_MAP_KEY } from "../utils/constants";

const StyledContainer = styled(Flex)`
  min-width: 300px;
  width: 80vw;
  max-width: 600px;
  margin: 0 auto;
  .ant-card, .share-buttons {
    width: 100%;
  }
  .winer {
    color: red;
    position: relative;
  }
`;

type Result = {
  winer: string;
  score: number;
}

function getMatchKey(player1: BasePlayer, player2: BasePlayer) {
  return `${player1.uid}-${player2.uid}`;
}

function initResultMap() {
  const cache = localStorage.getItem('match-result-map');
  const cacheEntries: [string, Result][] = cache ? Object.entries(JSON.parse(cache)) : [];
  return new Map<string, {
    winer: string,
    score: number,
  }>(cacheEntries);
}

const buildMatchGroupTable = (list: (BasePlayer | null)[], resultMap: Map<string, Result>) => {
  const roundNum = list.length - 1;
  const dataList = cloneDeep(list);
  const roundTable = new Array(roundNum).fill(0).map((_, i) => {
    const [left, right] = getRoundTable(dataList, i);
    left?.forEach((l, i) => {
      const r = right?.[i];
      const key = getMatchKey(l!, r!);
      const winer = resultMap.get(key)?.winer;
      const score = resultMap.get(key)?.score;
      if (winer && l && r) {
        if (winer === l?.uid) {
          l.score = (+l.score + (score ?? 0)).toFixed();
          r.score = (+r.score - (score ?? 0)).toFixed();
        } else {
          r.score = (+r.score + (score ?? 0)).toFixed();
          l.score = (+l.score - (score ?? 0)).toFixed();
        }
      }
    });
    return cloneDeep([left, right]);
  });
  const cache = JSON.stringify(Object.fromEntries(resultMap.entries()));
  localStorage.setItem(MATCH_RESULT_MAP_KEY, cache);
  return roundTable;
};

function BattleTable({
  players: list,
}: {
  players: BasePlayer[];
}) {
  const playerList = useMemo(() => list.length % 2 === 0 ? list : [...list, {
    uid: '',
    score: '',
    name: '-',
  }], [list]);
  const resultMap = useMemo(() => initResultMap(), []);
  const [matchGroupTable, setMatchGroupTable] = useState<ReturnType<typeof buildMatchGroupTable>>([]);
  const matchKeys = useMemo(() => {
    const keys: string[] = [];
    matchGroupTable.forEach(([left, right]) => {
      left?.forEach((l, i) => {
        const r = right?.[i];
        const key = getMatchKey(l!, r!);
        keys.push(key);
      });
    });
    return keys;
  }, [matchGroupTable]);
  const handleWiner = useCallback((l?: BasePlayer, r?: BasePlayer, winer?: BasePlayer, loser?: BasePlayer) => {
    if (!l?.uid || !r?.uid || !winer?.uid || !loser?.uid) return;
    const key = getMatchKey(l!, r!);
    const score = calculate(+winer.score, +loser.score);
    if (resultMap.get(key)?.winer) {
      resultMap.delete(key);
    } else {
      resultMap.set(key, { winer: winer?.uid!, score });
    }
    setMatchGroupTable(buildMatchGroupTable(playerList, resultMap));
  }, [playerList, resultMap]);
  const handleClear = useCallback((left?: (BasePlayer | null | undefined)[], right?: (BasePlayer | null | undefined)[]) => {
    left?.forEach((l, i) => {
      const r = right?.[i];
      const key = getMatchKey(l!, r!);
      resultMap.delete(key);
    });
    setMatchGroupTable(buildMatchGroupTable(playerList, resultMap));
  }, [playerList, resultMap]);
  const handleClearAll = useCallback(() => {
    matchGroupTable.forEach(([left, right]) => {
      left?.forEach((l, i) => {
        const r = right?.[i];
        const key = getMatchKey(l!, r!);
        resultMap.delete(key);
      });
    });
    setMatchGroupTable(buildMatchGroupTable(playerList, resultMap));
  }, [matchGroupTable, playerList, resultMap]);
  const scoreDiff = useMemo(() => {
    const [left = [], right = []] = matchGroupTable?.[matchGroupTable.length - 1] ?? [];
    const newScoreMap = Object.fromEntries([...left, ...right].map(e => [e?.uid, e?.score]));
    return newScoreMap;
  }, [playerList, matchGroupTable]);
  const [modal, contextHodler] = Modal.useModal();
  const eventId = useLocation().pathname.split('/').pop() ?? '';
  const handleShareCode = useCallback(async () => {
    const entries = matchKeys.map(e => [e, resultMap.get(e)]);
    const data = JSON.stringify(Object.fromEntries(entries));
    const code = await fetch(`/api/battle/${eventId}`, {
      method: 'PUT',
      body: JSON.stringify({ data }),
    }).then(res => res.json()).then(json => json.code);
    modal.success({
      maskClosable: true,
      icon: null,
      footer: null,
      style: { width: 300, height: 300 },
      title: '分享码',
      content: (
        <Flex vertical align="center" justify="center">
          <Typography.Text copyable>{code}</Typography.Text>
        </Flex>
      ),
    });
  }, [resultMap, matchKeys, eventId]);
  const [importCodeModalVisible, setImportModalVisible] = useState(false);
  const handleImportCodeClick = useCallback(() => {
    setImportModalVisible(true);
  }, []);
  const handleScanModalClose = useCallback(() => {
    setImportModalVisible(false);
  }, []);
  useEffect(() => {
    const roundTable = buildMatchGroupTable(playerList, resultMap);
    setMatchGroupTable(roundTable);
  }, [playerList, resultMap]);
  const [shareCode, setShareCode] = useState('');
  const handleImportCode = useCallback(async () => {
    const data: Record<string, Result> = await fetch(`/api/battle/${eventId}?code=${shareCode}`)
      .then(res => res.json())
      .then(json => json);
    Object.entries(data).forEach(([k, v]) => {
      const { winer = '', score = 0 } = v ?? {};
      resultMap.set(k, { winer, score });
    });
    setMatchGroupTable(buildMatchGroupTable(playerList, resultMap));
    setImportModalVisible(false);
  }, [shareCode, playerList]);
  // console.debug('matchGroupTable', matchGroupTable, gameResultMap);
  return (
    <StyledContainer vertical gap={12} justify="center" align="center">
      {contextHodler}
      <Modal
        forceRender
        title="导入分享码"
        open={importCodeModalVisible}
        onCancel={handleScanModalClose}
        onOk={handleImportCode}
        okText="导入"
        cancelText="取消"
      >
        <Flex vertical align="center" justify="center">
          <Input
            allowClear
            value={shareCode}
            placeholder="输入分享码"
            onChange={e => setShareCode(e.target.value)}
            onPressEnter={handleImportCode}
          />
        </Flex>
      </Modal>
      {matchGroupTable.map(([left, right], i) => {
        return (
          <Card
            size="small"
            key={`round-${i}`}
            title={`第 ${i + 1} 轮`}
            extra={<Button type="link" onClick={() => handleClear(left, right)} icon={<ClearOutlined />}>清除本轮</Button>}
          >
            {left?.map((l, i) => {
              const r = right?.[i];
              const key = `${l?.uid}-${r?.uid}`;
              const winer = resultMap.get(key)?.winer;
              const score = resultMap.get(key)?.score;
              const resultL = winer ? winer === l?.uid ? ` +${score}` : `-${score}` : ''
              const resultR = winer ? winer === r?.uid ? ` +${score}` : `-${score}` : ''
              const nameL = l?.uid ? `${l?.name}(${l?.score})${resultL}` : '-';
              const nameR = r?.uid ? `${r?.name}(${r?.score})${resultR}` : '-';
              return (
                <div key={key} className="round-row">
                  <Flex align="center" justify="space-between">
                    <div
                      className={winer === l?.uid ? 'winer' : ''}
                      onClick={() => handleWiner(l!, r!, l!, r!)}
                      style={{
                        flex: 5,
                        textAlign: 'center',
                      }}
                    >{nameL}</div>
                    <div style={{
                      flex: 1,
                      textAlign: 'center',
                    }}>-</div>
                    <div
                      className={winer === r?.uid ? 'winer' : ''}
                      onClick={() => handleWiner(l!, r!, r!, l!)}
                      style={{
                        flex: 5,
                        textAlign: 'center',
                      }}
                    >{nameR}</div>
                  </Flex>
                  {i < left.length - 1 && <Divider size="small" />}
                </div>
              );
            })}
          </Card>
        );
      })}
      <Card
        title={'积分增减预测'}
        extra={(
          <Button type="link" icon={<ClearOutlined />} onClick={handleClearAll}>清除本组所有</Button>
        )}
      >
        <Table
          className="score-table"
          showHeader={false}
          pagination={false}
          rowHoverable={false}
          size="small"
          dataSource={playerList}
          rowKey={e => e.uid}
          style={{ width: '100%' }}
          columns={[
            { dataIndex: 'name', align: 'center', },
            { dataIndex: 'score', align: 'center', },
            { dataIndex: 'uid', align: 'center', render: (uid, { score }) => scoreDiff[uid] || score },
            { dataIndex: 'uid', align: 'right', render: (uid, { score }) => {
              const diff = +(scoreDiff[uid] || score) - +score;
              return diff > 0 ? `+${diff}` : diff;
            } },
          ]}
        />
      </Card>
      <Flex className="share-buttons" gap={24} align="center" justify="space-between">
        <Flex flex={1}>
          <Button block onClick={handleShareCode} icon={<ShareAltOutlined />}>生成分享码</Button>
        </Flex>
        <Flex flex={1}>
          <Button block onClick={handleImportCodeClick} icon={<EditOutlined />}>输入分享码</Button>
        </Flex>
      </Flex>
    </StyledContainer>
  );
}

export default BattleTable;