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

import {
  sendHsNotReady,
  sendHsReady,
  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,
  Tooltip,
} from "antd";
import classNames from "classnames";
import { forwardRef, 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, SpecialButton } 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);
  const navigate = useNavigate();
  // ref.current?.getMoraResult(); // 用这个来异步获取猜拳结果

  const onClick = async () => {
    console.log(await ref.current?.getMoraResult());
  };

  return (
    <ConfigProvider theme={theme}>
      <div
        className={classNames(styles.container, {
          [styles.collapsed]: collapsed,
        })}
      >
        <Background />
        <div className={styles.sider}>
          <Chat />
        </div>
        <div className={styles.content}>
          {/* <div className={styles["status-bar"]}>
            <LoadingOutlined />
            对方正在选择先后
          </div> */}
          <div className={styles["btns-side"]}>
            <Tooltip title="退出房间" placement="right">
              <Button
                className={styles["btn"]}
                danger
                icon={<IconFont type="icon-exit" size={16} />}
                onClick={() => {
                  // 断开websocket🔗，
                  socketMiddleWare({ cmd: socketCmd.DISCONNECT });
                  // 返回上一个路由
                  navigate("..");
                }}
              />
            </Tooltip>
            <Button
              className={styles["btn"]}
              icon={<IconFont type="icon-side-bar-fill" size={16} />}
              onClick={() => setCollapsed(!collapsed)}
            />
          </div>

          <div className={styles.wrap}>
            <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={() => {
                        if (
                          room.getMePlayer()?.state === PlayerState.NO_READY
                        ) {
                          sendUpdateDeck(deck);
                          window.myExtraDeckCodes = [...deck.extra];
                          sendHsReady();
                        } else {
                          sendHsNotReady();
                        }
                      }}
                    >
                      {room.getMePlayer()?.state === PlayerState.NO_READY
                        ? "决斗准备"
                        : "取消准备"}
                    </Button>
                    {/* <MoraButton ref={ref} /> */}
                  </>
                }
              />
              <PlayerZone who={Who.Op} player={room.getOpPlayer()} />
            </div>
            <MoraPopover ref={ref}>
              <SpecialButton
                className={styles["btns-action"]}
                onClick={onClick}
              >
                <IconFont type="icon-play" size={12} />
                开始游戏
              </SpecialButton>
            </MoraPopover>
          </div>
        </div>
      </div>
    </ConfigProvider>
  );
};

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

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

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

const MoraPopover = forwardRef<MoraButtonRef, React.PropsWithChildren>(
  ({ children }, 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"
      >
        {children}
      </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);
  return (
    <Space>
      <Select
        title="卡组"
        showSearch
        style={{ width: 250 }}
        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>
    </Space>
  );
};
