import {
  ChatType,
  FileElement,
  GrayTipElement,
  InstanceContext,
  JsonGrayBusiId,
  MessageElement,
  NapCatCore,
  NTGrayTipElementSubTypeV2,
  RawMessage,
  TipGroupElement,
  TipGroupElementType,
} from 'napcat-core';
import { OB11GroupBanEvent } from '@/napcat-onebot/event/notice/OB11GroupBanEvent';
import fastXmlParser from 'fast-xml-parser';
import { OB11GroupMsgEmojiLikeEvent } from '@/napcat-onebot/event/notice/OB11MsgEmojiLikeEvent';
import { MessageUnique } from 'napcat-common/src/message-unique';
import { OB11GroupCardEvent } from '@/napcat-onebot/event/notice/OB11GroupCardEvent';
import { OB11GroupPokeEvent } from '@/napcat-onebot/event/notice/OB11PokeEvent';
import { OB11GroupEssenceEvent } from '@/napcat-onebot/event/notice/OB11GroupEssenceEvent';
import { OB11GroupTitleEvent } from '@/napcat-onebot/event/notice/OB11GroupTitleEvent';
import { OB11GroupGrayTipEvent } from '@/napcat-onebot/event/notice/OB11GroupGrayTipEvent';
import { OB11GroupUploadNoticeEvent } from '../event/notice/OB11GroupUploadNoticeEvent';
import { OB11GroupNameEvent } from '../event/notice/OB11GroupNameEvent';
import { FileNapCatOneBotUUID } from 'napcat-common/src/file-uuid';
import { OB11GroupIncreaseEvent } from '../event/notice/OB11GroupIncreaseEvent';
import { NapProtoMsg } from 'napcat-protobuf';
import { GroupReactNotify, PushMsg } from 'napcat-core/packet/transformer/proto';
import { NapCatOneBot11Adapter } from '..';

export class OneBotGroupApi {
  obContext: NapCatOneBot11Adapter;
  core: NapCatCore;
  constructor (obContext: NapCatOneBot11Adapter, core: NapCatCore) {
    this.obContext = obContext;
    this.core = core;
  }

  async parseGroupBanEvent (GroupCode: string, grayTipElement: GrayTipElement) {
    const groupElement = grayTipElement?.groupElement;
    if (!groupElement?.shutUp) return undefined;
    const memberUid = groupElement.shutUp.member.uid;
    const adminUid = groupElement.shutUp.admin.uid;
    let memberUin: string;
    let duration = parseInt(groupElement.shutUp.duration);
    const subType: 'ban' | 'lift_ban' = duration > 0 ? 'ban' : 'lift_ban';
    if (memberUid) {
      memberUin = (await this.core.apis.GroupApi.getGroupMember(GroupCode, memberUid))?.uin ?? '';
    } else {
      memberUin = '0';  // 0表示全员禁言
      if (duration > 0) {
        duration = -1;
      }
    }
    await this.core.apis.GroupApi.refreshGroupMemberCachePartial(GroupCode, memberUid);
    const adminUin = (await this.core.apis.GroupApi.getGroupMember(GroupCode, adminUid))?.uin;
    if (memberUin && adminUin) {
      return new OB11GroupBanEvent(
        this.core,
        parseInt(GroupCode),
        parseInt(memberUin),
        parseInt(adminUin),
        duration,
        subType
      );
    }
    return undefined;
  }

  async parseGroupEmojiLikeEventByGrayTip (
    groupCode: string,
    grayTipElement: GrayTipElement
  ) {
    if (this.core.apis.PacketApi.packetStatus === true) {
      return;
      // Raw包解析支持时禁用NT解析
    }
    const emojiLikeData = new fastXmlParser.XMLParser({
      ignoreAttributes: false,
      attributeNamePrefix: '',
    }).parse(grayTipElement.xmlElement.content);
    this.core.context.logger.logDebug('收到表情回应我的消息', emojiLikeData);
    const senderUin = emojiLikeData.gtip.qq.jp;
    const msgSeq = emojiLikeData.gtip.url.msgseq;
    const emojiId = emojiLikeData.gtip.face.id;
    return await this.createGroupEmojiLikeEvent(groupCode, senderUin, msgSeq, emojiId, true, 1);
  }

  async createGroupEmojiLikeEvent (
    groupCode: string,
    senderUin: string,
    msgSeq: string,
    emojiId: string,
    isAdd: boolean = true,
    count: number = 1
  ) {
    const peer = {
      chatType: ChatType.KCHATTYPEGROUP,
      guildId: '',
      peerUid: groupCode,
    };
    const replyMsgList = (await this.core.apis.MsgApi.queryFirstMsgBySeq(peer, msgSeq)).msgList;
    if (replyMsgList.length < 1) {
      return;
    }
    const replyMsg = replyMsgList[0];
    if (!replyMsg) {
      this.core.context.logger.logError('解析表情回应消息失败: 未找到回应消息');
      return undefined;
    }
    return new OB11GroupMsgEmojiLikeEvent(
      this.core,
      parseInt(groupCode),
      parseInt(senderUin),
      MessageUnique.createUniqueMsgId({ chatType: ChatType.KCHATTYPEGROUP, guildId: '', peerUid: groupCode }, replyMsg.msgId),
      [{
        emoji_id: emojiId,
        count,
      }],
      isAdd,
      msgSeq
    );
  }

  async parseCardChangedEvent (msg: RawMessage) {
    if (msg.senderUin && msg.senderUin !== '0') {
      const member = await this.core.apis.GroupApi.getGroupMember(msg.peerUid, msg.senderUin);
      if (member && member.cardName !== msg.sendMemberName) {
        const newCardName = msg.sendMemberName ?? '';
        const event = new OB11GroupCardEvent(this.core, parseInt(msg.peerUid), parseInt(msg.senderUin), newCardName, member.cardName);
        member.cardName = newCardName;
        return event;
      }
      if (member && member.nick !== msg.sendNickName) {
        await this.core.apis.GroupApi.refreshGroupMemberCachePartial(msg.peerUid, msg.senderUid);
      }
    }
    return undefined;
  }

  async registerParseGroupReactEvent () {
    this.obContext.core.context.packetHandler.onCmd('trpc.msg.olpush.OlPushService.MsgPush', async (packet) => {
      const data = new NapProtoMsg(PushMsg).decode(Buffer.from(packet.hex_data, 'hex'));
      if (data.message.contentHead.type === 732 && data.message.contentHead.subType === 16) {
        const pbNotify = data.message.body?.msgContent?.slice(7);
        if (!pbNotify) {
          return;
        }
        // 开始解析Notify
        const notify = new NapProtoMsg(GroupReactNotify).decode(pbNotify);
        if ((notify.field13 ?? 0) === 35) {
          // Group React Notify
          const groupCode = notify.groupUin?.toString() ?? '';
          const operatorUid = notify.groupReactionData?.data?.data?.groupReactionDataContent?.operatorUid ?? '';
          const type = notify.groupReactionData?.data?.data?.groupReactionDataContent?.type ?? 0;
          const seq = notify.groupReactionData?.data?.data?.groupReactionTarget?.seq?.toString() ?? '';
          const code = notify.groupReactionData?.data?.data?.groupReactionDataContent?.code ?? '';
          // const count = notify.groupReactionData?.data?.data?.groupReactionDataContent?.count ?? 0;
          const senderUin = await this.core.apis.UserApi.getUinByUidV2(operatorUid);
          const event = await this.createGroupEmojiLikeEvent(
            groupCode,
            senderUin,
            seq,
            code,
            type === 1,
            1
          );
          if (event) {
            this.obContext.networkManager.emitEvent(event);
          }
        }
      }
    });
  }

  async registerParseGroupReactEventByCore () {
    this.core.event.on('event:emoji_like', async (data) => {
      const event = await this.createGroupEmojiLikeEvent(
        data.groupId,
        data.senderUin,
        data.msgSeq,
        data.emojiId,
        data.isAdd,
        data.count
      );
      if (event) {
        this.obContext.networkManager.emitEvent(event);
      }
    });
  }

  async parsePaiYiPai (msg: RawMessage, jsonStr: string) {
    const json = JSON.parse(jsonStr);
    // 判断业务类型
    // Poke事件
    const pokedetail: Array<{ uid: string; }> = json.items;
    // 筛选item带有uid的元素
    const poke_uid = pokedetail.filter(item => item.uid);
    if (poke_uid.length === 2 && poke_uid[0]?.uid && poke_uid[1]?.uid) {
      return new OB11GroupPokeEvent(
        this.core,
        parseInt(msg.peerUid),
        +await this.core.apis.UserApi.getUinByUidV2(poke_uid[0].uid),
        +await this.core.apis.UserApi.getUinByUidV2(poke_uid[1].uid),
        pokedetail
      );
    }
    return undefined;
  }
  async parseOtherJsonEvent (msg: RawMessage, jsonGrayTipElement: GrayTipElement['jsonGrayTipElement'], context: InstanceContext) {
    let json: { items?: { txt?: string; param?: string[] }[] };
    try {
      json = JSON.parse(jsonGrayTipElement.jsonStr);
    } catch (e) {
      context.logger.logWarn('灰条消息JSON解析失败', jsonGrayTipElement.jsonStr, e);
      return undefined;
    }
    const type = json.items?.[json.items.length - 1]?.txt;
    await this.core.apis.GroupApi.refreshGroupMemberCachePartial(msg.peerUid, msg.senderUid);
    if (type === '头衔') {
      const memberUin = json.items?.[1]?.param?.[0];
      const title = json.items?.[3]?.txt;
      context.logger.logDebug('收到群成员新头衔消息', json);
      if (memberUin == null || title == null) {
        context.logger.logWarn('收到格式异常的群成员新头衔灰条消息', json);
        return undefined;
      }
      return new OB11GroupTitleEvent(
        this.core,
        +msg.peerUid,
        +memberUin,
        title
      );
    } else if (type === '移出') {
      context.logger.logDebug('收到机器人被踢消息', json);
    } else {
      context.logger.logWarn('收到未知的灰条消息', json);

      // 如果有真实发送者（非0），生成事件上报，可用于检测和撤回伪造灰条
      const senderUin = Number(msg.senderUin) || 0;
      if (senderUin !== 0) {
        const peer = { chatType: ChatType.KCHATTYPEGROUP, guildId: '', peerUid: msg.peerUid };
        const messageId = MessageUnique.createUniqueMsgId(peer, msg.msgId);
        return new OB11GroupGrayTipEvent(
          this.core,
          +msg.peerUin,
          senderUin,
          messageId,
          jsonGrayTipElement.busiId,
          jsonGrayTipElement.jsonStr,
          {
            msgSeq: msg.msgSeq,
            msgTime: msg.msgTime,
            msgId: msg.msgId,
            json,
          }
        );
      }
    }
    return undefined;
  }

  async parseEssenceMsg (msg: RawMessage, jsonStr: string) {
    const json = JSON.parse(jsonStr);
    const searchParams = new URL(json.items[0].jp).searchParams;
    const msgSeq = searchParams.get('msgSeq')!;
    const Group = searchParams.get('groupCode');
    if (!Group) return undefined;
    // const businessId = searchParams.get('businessid');
    const Peer = {
      guildId: '',
      chatType: ChatType.KCHATTYPEGROUP,
      peerUid: Group,
    };
    const msgData = await this.core.apis.MsgApi.getMsgsBySeqAndCount(Peer, msgSeq.toString(), 1, true, true);
    const msgList = (await this.core.apis.WebApi.getGroupEssenceMsgAll(Group)).flatMap((e) => e.data.msg_list);
    const realMsg = msgList.find((e) => e.msg_seq.toString() === msgSeq);
    if (msgData.msgList[0]) {
      return new OB11GroupEssenceEvent(
        this.core,
        parseInt(msg.peerUid),
        MessageUnique.getShortIdByMsgId(msgData.msgList[0].msgId)!,
        parseInt(msgData.msgList[0].senderUin ?? await this.core.apis.UserApi.getUinByUidV2(msgData.msgList[0].senderUid)),
        parseInt(realMsg?.add_digest_uin ?? '0')
      );
    }
    return undefined;
    // 获取MsgSeq+Peer可获取具体消息
  }

  async parseGroupUploadFileEvene (msg: RawMessage, element: FileElement, elementWrapper: MessageElement) {
    return new OB11GroupUploadNoticeEvent(
      this.core,
      parseInt(msg.peerUid), parseInt(msg.senderUin || ''),
      {
        id: FileNapCatOneBotUUID.encode({
          chatType: ChatType.KCHATTYPEGROUP,
          peerUid: msg.peerUid,
        }, msg.msgId, elementWrapper.elementId, elementWrapper?.fileElement?.fileUuid, element.fileMd5 ?? element.fileUuid),
        name: element.fileName,
        size: parseInt(element.fileSize),
        busid: element.fileBizId ?? 0,
      }
    );
  }

  async parseGroupElement (msg: RawMessage, element: TipGroupElement, elementWrapper: GrayTipElement) {
    if (element.type === TipGroupElementType.KGROUPNAMEMODIFIED) {
      this.core.context.logger.logDebug('收到群名称变更事件', element);
      return new OB11GroupNameEvent(
        this.core,
        parseInt(msg.peerUid),
        parseInt(await this.core.apis.UserApi.getUinByUidV2(element.memberUid)),
        element.groupName
      );
    } else if (element.type === TipGroupElementType.KSHUTUP) {
      const event = await this.parseGroupBanEvent(msg.peerUid, elementWrapper);
      return event;
    } else if (element.type === TipGroupElementType.KMEMBERADD) {
      // 自己的通知 协议推送为type->85 在这里实现为了避免邀请出现问题
      if (element.memberUid === this.core.selfInfo.uid) {
        await this.core.apis.GroupApi.refreshGroupMemberCache(msg.peerUid, true);
        return new OB11GroupIncreaseEvent(
          this.core,
          parseInt(msg.peerUid),
          +this.core.selfInfo.uin,
          element.adminUid ? +await this.core.apis.UserApi.getUinByUidV2(element.adminUid) : 0,
          'approve'
        );
      }
    }
    return undefined;
  }

  async parseSelfInviteEvent (msg: RawMessage, inviterUin: string, inviteeUin: string) {
    return new OB11GroupIncreaseEvent(
      this.core,
      parseInt(msg.peerUid),
      +inviteeUin,
      +inviterUin,
      'invite'
    );
  }

  async parse51TypeEvent (msg: RawMessage, grayTipElement: GrayTipElement) {
    // 神经腾讯 没了妈妈想出来的
    // Warn 下面存在高并发危险
    if (grayTipElement.jsonGrayTipElement.jsonStr) {
      const json: {
        align: string,
        items: Array<{ txt: string, type: string; }>;
      } = JSON.parse(grayTipElement.jsonGrayTipElement.jsonStr);
      if (json.items.length === 1 && json.items[0]?.txt.endsWith('加入群')) {
        const old_members = structuredClone(this.core.apis.GroupApi.groupMemberCache.get(msg.peerUid));
        if (!old_members) return;
        const new_members_map = await this.core.apis.GroupApi.refreshGroupMemberCache(msg.peerUid, true);
        if (!new_members_map) return;
        const new_members = Array.from(new_members_map.values());
        // 对比members查找新成员
        const new_member = new_members.find((member) => old_members.get(member.uid) === undefined);
        if (!new_member) return;
        return new OB11GroupIncreaseEvent(
          this.core,
          +msg.peerUid,
          +new_member.uin,
          0,
          'invite'
        );
      }
    }
    return undefined;
  }

  async parseGrayTipElement (msg: RawMessage, grayTipElement: GrayTipElement) {
    if (grayTipElement.subElementType === NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_GROUP) {
      // 解析群组事件 由sysmsg解析
      return await this.parseGroupElement(msg, grayTipElement.groupElement, grayTipElement);
    } else if (grayTipElement.subElementType === NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_XMLMSG) {
      // 筛选自身入群情况
      // if (grayTipElement.xmlElement.busiId === '10145') {
      //     const inviteData = new fastXmlParser.XMLParser({
      //         ignoreAttributes: false,
      //         attributeNamePrefix: '',
      //     }).parse(grayTipElement.xmlElement.content);

      //     const inviterUin: string = inviteData.gtip.qq[0].jp;
      //     const inviteeUin: string = inviteData.gtip.qq[1].jp;
      //     //刷新群缓存
      //     if (inviteeUin === this.core.selfInfo.uin) {
      //         this.core.apis.GroupApi.refreshGroupMemberCache(msg.peerUid).then().catch();
      //         return this.parseSelfInviteEvent(msg, inviterUin, inviteeUin);
      //     }
      // } else
      if (grayTipElement.xmlElement?.templId === '10382') {
        return await this.obContext.apis.GroupApi.parseGroupEmojiLikeEventByGrayTip(msg.peerUid, grayTipElement);
      } else {
        // return await this.obContext.apis.GroupApi.parseGroupIncreaseEvent(msg.peerUid, grayTipElement);
      }
    } else if (grayTipElement.subElementType === NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_JSON) {
      // 解析json事件 busiId好像是string类型的？
      if (grayTipElement.jsonGrayTipElement.busiId === '1061') {
        return await this.parsePaiYiPai(msg, grayTipElement.jsonGrayTipElement.jsonStr);
      } else if (grayTipElement.jsonGrayTipElement.busiId === JsonGrayBusiId.AIO_GROUP_ESSENCE_MSG_TIP.toString()) {
        return await this.parseEssenceMsg(msg, grayTipElement.jsonGrayTipElement.jsonStr);
      } else if (grayTipElement.jsonGrayTipElement.busiId === '51') {
        // 51是什么？{"align":"center","items":[{"txt":"下一秒起床通过王者荣耀加入群","type":"nor"}]
        return await this.parse51TypeEvent(msg, grayTipElement);
      } else {
        console.log('Unknown JSON event:', grayTipElement.jsonGrayTipElement, JSON.stringify(grayTipElement));
        return await this.parseOtherJsonEvent(msg, grayTipElement.jsonGrayTipElement, this.core.context);
      }
    }
    return undefined;
  }
}
