import { CheckCircleFilled } from "@ant-design/icons";

import {
  sendHsNotReady,
  sendHsReady,
  sendHsStart,
  sendHsToDuelList,
  sendHsToObserver,
  sendUpdateDeck,
  ygopro,
} from "@/api";
import socketMiddleWare, { socketCmd } from "@/middleware/socket";
import PlayerState = ygopro.StocHsPlayerChange.State;
import SelfType = ygopro.StocTypeChange.SelfType;
import { Avatar, Button, ConfigProvider, Popover, Skeleton, Space } from "antd";
import classNames from "classnames";
import {
  forwardRef,
  useEffect,
  useImperativeHandle,
  useRef,
  useState,
} from "react";
import { useNavigate } from "react-router-dom";
import { useSnapshot } from "valtio";

import { useConfig } from "@/config";
import { accountStore, deckStore, IDeck, Player, roomStore } from "@/stores";
import { Background, IconFont, Select } from "@/ui/Shared";

import { Chat } from "./Chat";
import styles from "./index.module.scss";

const NeosConfig = useConfig();

const theme = {
  components: {
    Button: {
      lineWidth: 0,
      fontSizeLG: 14,
      fontSize: 12,
      colorBgContainer: "hsla(0, 0%, 100%, 0.05)",
      colorPrimaryHover: "#ccc",
      colorPrimaryActive: "#aaa",
    },
    Popover: {
      colorBgElevated: "hsla(0, 0%, 100%, 0.1)",
    },
  },
};

export const Component: React.FC = () => {
  const { user } = useSnapshot(accountStore);
  const [collapsed, setCollapsed] = useState(false);
  const { decks } = useSnapshot(deckStore);
  const [deck, setDeck] = useState<IDeck>(JSON.parse(JSON.stringify(decks[0])));
  const room = useSnapshot(roomStore);
  // const ref = useRef<MoraButtonRef>(null);
  // ref.current?.getMoraResult(); // 用这个来异步获取猜拳结果

  useEffect(() => {
    sendUpdateDeck(deck);
    window.myExtraDeckCodes = [...deck.extra];
  }, [deck]);

  return (
    <ConfigProvider theme={theme}>
      <div
        className={classNames(styles.container, {
          [styles.collapsed]: collapsed,
        })}
      >
        <Background />
        <div className={styles.sider}>
          <Button
            className={styles["btn-sider"]}
            icon={<IconFont type="icon-side-bar-fill" size={16} />}
            onClick={() => setCollapsed(!collapsed)}
          />
          <Chat />
        </div>
        <div className={styles.main}>
          {/* <div className={styles["status-bar"]}>
            <LoadingOutlined />
            对方正在选择先后
          </div> */}
          <Controller
            onDeckChange={(deckName: string) => {
              const deck = deckStore.get(deckName);
              // 同步后端
              if (deck) {
                setDeck(deck);
              } else {
                alert(`Deck ${deckName} not found`);
              }
            }}
          />
          <div className={styles["both-side-container"]}>
            <PlayerZone
              who={Who.Me}
              player={room.getMePlayer()}
              avatar={user?.avatar_url}
              btn={
                <>
                  <Button
                    size="large"
                    className={styles["btn-join"]}
                    onClick={() => {
                      room.getMePlayer()?.state === PlayerState.NO_READY
                        ? sendHsReady()
                        : sendHsNotReady();
                    }}
                  >
                    {room.getMePlayer()?.state === PlayerState.NO_READY
                      ? "决斗准备"
                      : "取消准备"}
                  </Button>
                  {/* <MoraButton ref={ref} /> */}
                </>
              }
            />
            <PlayerZone who={Who.Op} player={room.getOpPlayer()} />
          </div>
        </div>
      </div>
    </ConfigProvider>
  );
};

enum Mora {
  Rock = "rock",
  Scissors = "scissors",
  Paper = "paper",
}

// TODO: 可能有更好的设计，不一定是放在这个按钮这儿
// 思路不变，先暂时这么写

interface MoraButtonRef {
  getMoraResult: () => Promise<Mora>;
}

const MoraButton = forwardRef<MoraButtonRef, {}>((props, ref) => {
  const [open, setOpen] = useState(false);

  const resolve = useRef<(mora: Mora) => void>(() => {});

  useImperativeHandle(ref, () => ({
    async getMoraResult() {
      setOpen(true);
      const result = await new Promise<Mora>((rs) => (resolve.current = rs));
      setOpen(false);
      return result;
    },
  }));

  const onMoraClick = (mora: Mora) => resolve.current(mora);

  const map = {
    [Mora.Rock]: "石头",
    [Mora.Scissors]: "剪刀",
    [Mora.Paper]: "布",
  };

  return (
    <Popover
      overlayStyle={{ backdropFilter: "blur(10px)" }}
      content={
        <Space>
          {[Mora.Rock, Mora.Scissors, Mora.Paper].map((mora) => (
            <Button
              key={mora}
              size="large"
              type="text"
              icon={<IconFont type={`icon-hand-${mora}`} size={16} />}
              onClick={() => onMoraClick(mora)}
            >
              {map[mora]}
            </Button>
          ))}
        </Space>
      }
      open={open}
      placement="bottom"
    >
      <Button
        size="large"
        className={styles["btn-join"]}
        icon={<IconFont type="icon-mora" size={20} />}
      >
        猜拳
      </Button>
    </Popover>
  );
});

const OrderPopup: React.FC<React.PropsWithChildren<{ open: boolean }>> = ({
  children,
  open,
}) => {
  return (
    <Popover
      overlayStyle={{ backdropFilter: "blur(10px)" }}
      open={open}
      content={
        <Space>
          <Button
            size="large"
            type="text"
            icon={<IconFont type="icon-one" size={18} />}
          >
            先手
          </Button>
          <Button
            size="large"
            type="text"
            icon={<IconFont type="icon-two" size={18} />}
          >
            后手
          </Button>
        </Space>
      }
      trigger="focus"
      placement="bottom"
    >
      {children}
    </Popover>
  );
};

enum Who {
  Me = "me",
  Op = "op",
}

// 玩家区域: 两侧各有一个
const PlayerZone: React.FC<{
  btn?: React.ReactNode; // 在内部右侧可以放一个按钮
  who?: Who;
  player?: Player;
  avatar?: string; // 因为对手的头像目前不清楚如何获取，因此暂时这里作为一个参数传入
}> = ({ btn, who, player, avatar }) => {
  return (
    <div className={classNames(styles["side-box"], who && styles[who])}>
      <div className={styles.inner}></div>
      <OrderPopup open={false}>
        <div style={{ position: "relative" }}>
          <Avatar
            src={
              avatar && player
                ? avatar
                : player && player.state != PlayerState.LEAVE
                ? `${NeosConfig.assetsPath}/default-avatar.png`
                : ""
            }
            size={48}
          />
          {player?.state === PlayerState.READY && (
            <CheckCircleFilled className={styles.check} />
          )}
        </div>
      </OrderPopup>
      <div className={styles.name}>
        {player && player.state != PlayerState.LEAVE ? (
          player.name
        ) : (
          <Skeleton.Input size="small" />
        )}
      </div>
      {btn}
    </div>
  );
};

const Controller: React.FC<{ onDeckChange: (deckName: string) => void }> = ({
  onDeckChange,
}) => {
  const snapDeck = useSnapshot(deckStore);
  const snapRoom = useSnapshot(roomStore);
  const navigate = useNavigate();
  return (
    <Space>
      <Select
        title="卡组"
        showSearch
        style={{ width: 300 }}
        defaultValue={snapDeck.decks[0].deckName}
        options={snapDeck.decks.map((deck) => ({
          value: deck.deckName,
          title: deck.deckName,
        }))}
        onChange={
          // @ts-ignore
          (value) => onDeckChange(value)
        }
      />
      <Button
        size="large"
        icon={<IconFont type="icon-record" size={18} />}
        onClick={() => {
          if (snapRoom.selfType != SelfType.OBSERVER) {
            sendHsToObserver();
          } else {
            sendHsToDuelList();
          }
        }}
      >
        {snapRoom.selfType == SelfType.OBSERVER ? "加入决斗者" : "加入观战"}
        <Avatar.Group className={styles["avatars-watch"]}>
          {Array.from({ length: snapRoom.observerCount }).map((_, idx) => (
            <Avatar
              key={idx}
              src={`${NeosConfig.assetsPath}/default-avatar.png`}
              size="small"
            />
          ))}
        </Avatar.Group>
      </Button>
      <Button
        size="large"
        icon={<IconFont type="icon-play" size={12} />}
        disabled={!snapRoom.isHost}
        onClick={() => sendHsStart()}
      >
        开始游戏
      </Button>
      <Button
        size="large"
        danger
        onClick={() => {
          // 断开websocket🔗，
          socketMiddleWare({ cmd: socketCmd.DISCONNECT });
          // 返回上一个路由
          navigate("..");
        }}
      >
        退出房间
      </Button>
    </Space>
  );
};
