import { Injectable } from '@angular/core';
import { HttpService } from './http.service';
import * as Parse from 'parse';
import { AlertController, ToastController } from '@ionic/angular';
// import AgoraRTM from 'agora-rtmClient';
import { Subject } from 'rxjs';
import { Router } from '@angular/router';
declare const AgoraRTM: any;
@Injectable({
  providedIn: 'root',
})
export class MessageService {
  private eventSource = new Subject<any>();
  event$ = this.eventSource.asObservable();
  company: string = 'Qje9D4bqol';
  rtmClient: any; // RTM实例
  // rtmClientMap: any = {};
  channelNameList: any = {}; //订阅频道状态
  msChannelName: string = 'global_room'; // 全球频道
  options: any = {
    connectState: false,
  };
  appid?: string;
  userId: string = Parse.User.current()?.id!;

  pageFun?: Function; //页面传入的方法
  alert: any; // 弹窗

  constructor(
    private alertController: AlertController,
    private router: Router,
    public toastController: ToastController,
    private http: HttpService
  ) {}
  messageMapList: any = {
    global_room: [
      // 世界频道消息列表
      // {
      //   is_self: true,
      //   avatar:
      //     'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
      //   msg_type: 1,
      //   content: 'nihao',
      //   istoday: true,
      //   timestamp: new Date(),
      // },
      // {
      //   is_self: true,
      //   avatar:
      //     'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
      //   msg_type: 1,
      //   content: `Use the pipe name to trace where the pipe is declared and used. To resolve this error: If the pipe is local to the NgModule, give it a unique name in the pipe's decorator and declared it in the NgModule. If the pipe is standalone or is declared in another NgModule, add it to the imports field of the standalone component or the current NgModule.`,
      //   istoday: true,
      //   timestamp: new Date(),
      // },
      // {
      //   is_self: true,
      //   avatar:
      //     'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
      //   msg_type: 1,
      //   content: `Use the pipe name to trace where the pipe is declared and used. To resolve this error: If the pipe is local to the NgModule, give it a unique name in the pipe's decorator and declared it in the NgModule. If the pipe is standalone or is declared in another NgModule, add it to the imports field of the standalone component or the current NgModule.`,
      //   istoday: true,
      //   timestamp: new Date(),
      // },
      // {
      //   is_self: true,
      //   avatar:
      //     'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
      //   msg_type: 1,
      //   content: `Use the pipe name to trace where the pipe is declared and used. To resolve this error: If the pipe is local to the NgModule, give it a unique name in the pipe's decorator and declared it in the NgModule. If the pipe is standalone or is declared in another NgModule, add it to the imports field of the standalone component or the current NgModule.`,
      //   istoday: true,
      //   timestamp: new Date(),
      // },
      // {
      //   is_self: false,
      //   avatar:
      //     'https://file-cloud.fmode.cn/Qje9D4bqol/20241109/2t1lp0032258601.png',
      //   msg_type: 1,
      //   content: 'nihao',
      //   istoday: true,
      //   timestamp: new Date(),
      // },
    ],
  };

  /* 获取token */
  async getToken(channel?: string) {
    this.userId = Parse.User.current()?.id!;
    //获取频道token记录
    let uid = Parse.User.current()?.id;
    let baseurl = 'https://server.fmode.cn/api/webrtc/build_token';
    let reqBody = {
      company: this.company,
      channelName: this.msChannelName,
      type: 'withrtm',
      account: uid,
    };
    let data: any = await this.http.httpRequst(baseurl, reqBody, 'POST');
    console.log(data);
    if (data.code == 200) {
      // this.options[channel] = {
      //   token: data.data.token,
      // };
      this.options.token = data.data.token;
      this.appid = data.data.appid;
    }
  }

  async initRTM(channelName: string) {
    // let states = ['CONNECTED', 'CONNECTING'];
    if (this.options.connectState) return;
    await this.getToken(channelName);
    // const rtmConfig = { logLevel: 'debug' };
    this.rtmClient = new AgoraRTM.RTM(this.appid, this.userId);
    this.joinReady();
    await this.loginRTM();
    // this.subscribeMessage(channelName);
    // this.publishMessage('user-online', channelName, 'USER'); //用户上线通知
  }
  /**@监听频道消息
   *@'USERCALLINVITATION': 用户通话邀请
   *@'CLOASEINVITATION': 取消通话邀请
   *@'REFUSEINVITATION_' + uid: 拒绝通话邀请
   *@'RESPONSEINVITOIN_' + uid: 接受邀请
   */
  joinReady(channelName?: string) {
    this.rtmClient?.addEventListener('message', async (event: any) => {
      console.log('接收到一条消息：', event);
      let states = [
        'USERCALLINVITATION',
        'REFUSEINVITATION_' + this.userId,
        'CLOASEINVITATION',
        'RESPONSEINVITOIN_' + this.userId,
      ];
      const message = JSON.parse(event.message);
      let is_self = event.publisher == this.userId;
      console.log('自己发出的消息：', is_self, message.text);
      if (!is_self && states.includes(message.text)) {
        this.callPresence(message.text, event.publisher, event.channelName);
        return;
      }
      this.showMessage(event);
    });
    this.rtmClient?.addEventListener('presence', (event: any) => {
      console.log('频道人员状态变化 ', event);
      let is_self = event.publisher == this.userId;
      //远端用户离开频道，主播在线状态
      if (
        !is_self &&
        event.eventType === 'REMOTE_LEAVE' &&
        event.channelName === this.userId
      ) {
        this.setConnectState(this.userId, 'ONLINE');
      }
    });
    this.rtmClient?.addEventListener('linkState', (event: any) => {
      console.log('连接状态: ', event);
    });
  }

  /* 设置频道状态 */
  async setConnectState(channelName: string, mode: string) {
    const channelType = 'MESSAGE';
    const states = {
      Mode: mode,
    };
    try {
      await this.rtmClient?.presence.setState(channelName, channelType, states);
    } catch (err: any) {
      console.log(err);
    }
  }

  /* 呼叫事件 */
  async callPresence(message: string, publisher: string, channelName: string) {
    console.log(message);
    let userData = await this.getUserMetadata(publisher);
    let toast;
    switch (message) {
      case 'USERCALLINVITATION':
        await this.setConnectState(this.userId, 'CONNECTING');
        console.log(`收到${userData.nickname.value ?? '未知用户'}通话邀请`);
        this.alert = await this.alertController.create({
          cssClass: 'my-custom-class',
          header: '通话邀请',
          message: `收到${userData.nickname.value ?? '未知用户'}通话邀请`,
          backdropDismiss: false,
          buttons: [
            {
              text: '拒绝',
              role: 'cancel',
              handler: async (blah) => {
                await this.setConnectState(this.userId, 'ONLINE');
                this.publishMessage(
                  'REFUSEINVITATION_' + publisher,
                  channelName
                );
              },
            },
            {
              text: '接受',
              cssClass: 'secondary',
              handler: async () => {
                this.publishMessage(
                  'RESPONSEINVITOIN_' + publisher,
                  channelName
                );
                let rid = await this.getRoom(this.userId);
                this.router.navigate(['live/link-room/' + rid]);
              },
            },
          ],
        });
        await this.alert.present();
        break;
      case 'CLOASEINVITATION':
        await this.setConnectState(this.userId, 'ONLINE');
        console.log(`${userData.nickname.value ?? '未知用户'}取消通话`);
        this.alert?.dismiss();
        toast = await this.toastController.create({
          message: '对方已取消通话邀请',
          color: 'warning',
          duration: 1500,
        });
        toast.present();
        break;
      case 'REFUSEINVITATION_' + this.userId:
        console.log(`${userData.nickname.value ?? '未知用户'}拒绝通话`);
        this.alert?.dismiss();
        this.eventSource.next(false);
        break;
      case 'RESPONSEINVITOIN_' + this.userId:
        console.log(
          `${userData.nickname.value ?? '未知用户'}同意通话，进入视频通话`
        );
        this.alert?.dismiss();
        this.eventSource.next(true);
        break;
    }
  }
  async getRoom(uid: string): Promise<string | undefined> {
    let query = new Parse.Query('Room');
    query.equalTo('company', this.company);
    query.equalTo('user', uid);
    query.notEqualTo('isDeleted', true);
    query.select('objectId');
    let r = await query.first();
    return r?.id;
  }
  /* 加入频道 */
  // async join(channelName: string) {
  //   const options = {
  //     token: this.options[channelName].token,
  //     withPresence: true,
  //     withLock: true,
  //     withMetadata: true,
  //   };
  //   try {
  //     const streamChannel =
  //       this.rtmClientMap[channelName].rtmClient.createStreamChannel(
  //         channelName
  //       );
  //     const result = await streamChannel.join(options);
  //   } catch (status) {
  //     console.error('join channel failed: ', status);
  //   }
  // }
  async loginRTM(channelName?: string) {
    try {
      await this.rtmClient?.login({
        token: this.options.token,
      });
      this.options.connectState = true; // 登录成功
      let userMateData = await this.getUserMetadata(this.userId);
      if (!userMateData) {
        let user = Parse.User.current();
        const metadata = [
          {
            key: 'nickname',
            value: user?.get('nickname'),
          },
          {
            key: 'avatar',
            value:
              user?.get('avatar') ??
              'https://file-cloud.fmode.cn/DXNgcD6zo6/20221202/j6p8kb034039.png',
          },
        ];
        const options = {
          userId: this.userId,
          addTimeStamp: true,
          addUserId: true,
        };
        let result = await this.rtmClient?.storage.setUserMetadata(
          metadata,
          options
        );
        console.log(JSON.stringify(result));
      }
    } catch (status) {
      console.log(status);
    }
  }
  logOutRTM() {
    this.rtmClient?.logout().then(() => {
      console.log('logout success');
      this.options.connectState = false;
    });
  }
  /* 订阅消息 */
  subscribeMessage(channelName: string, param?: any, callback?: any) {
    if (this.channelNameList[channelName]) return;
    return new Promise((resolve, reject) => {
      const options = {
        withMessage: param?.message ?? false, // message 事件
        withPresence: param?.presence ?? false, // presence 事件
        beQuiet: false, // quiet 事件
        withMetadata: false, // metadata 事件
        withLock: false, // lock 事件
      };
      this.rtmClient
        .subscribe(channelName, options)
        .then((res: any) => {
          console.log('subscribeMessage', res);
          //订阅成功
          this.channelNameList[channelName] = true;
          if (this.messageMapList[channelName]?.length === 0) {
            this.messageMapList[channelName] = [];
            this.getHistoryMessage(channelName)
          }
          this.pageFun?.();
          resolve(true);
        })
        .catch((err: any) => {
          console.error('subscribeMessageErr', err);
          reject(false);
        });
    });
  }

  async getHistoryMessage(channelName: string) {
    let query = new Parse.Query('MessageLog');
    query.equalTo('channel', channelName);
    query.descending('createdAt');
    query.skip(this.messageMapList[channelName].length);
    query.limit(50);
    query.select('content','from_id');
    let msgList = await query.find();
    msgList.forEach((item: any) => {
      let is_self = item?.get('from_id') == this.userId;
      let data: any = item?.get('content');
      data['is_self'] = is_self;
      data['istoday'] = true;
      data['timestamp'] = new Date(data.timestamp)
      this.messageMapList[channelName].push(data)
    });
    // this.messageMapList[channelName].unshift(...msgList);
  }
  /* 取消订阅 */
  unsubscribeMessage(channelName: string) {
    this.rtmClient
      .unsubscribe(channelName)
      .then((res: any) => {
        console.log('unsubscribeMessage', res);
        //订阅成功
        this.channelNameList[channelName] = false;
      })
      .catch((err: any) => {
        console.error('unsubscribeMessage', err);
      });
  }

  async showMessage(param: any) {
    let userData = await this.getUserMetadata(param.publisher);
    let is_self = param.publisher == this.userId;
    // console.log(userData);
    let message = JSON.parse(param.message);
    if (!this.messageMapList[param.channelName])
      this.messageMapList[param.channelName] = [];
    if (is_self) {
      this.saveMeesage({
        from_id: this.userId,
        from_username: Parse.User.current()?.get('nickname') ?? '未知用户',
        target_id: param.channelName,
        // target_name: userData.nickname.value ?? '未知用户',
        channel: param.channelName,
        content: {
          avatar:
            userData.avatar.value ??
            'https://file-cloud.fmode.cn/DXNgcD6zo6/20221202/j6p8kb034039.png',
          msg_type: 1,
          name: userData.nickname.value ?? '未知用户',
          content: message?.text ?? '',
          publisher: param.publisher,
          timestamp: param.timestamp,
        },
      });
    }
    let data: any = {
      is_self: is_self,
      avatar:
        userData.avatar.value ??
        'https://file-cloud.fmode.cn/DXNgcD6zo6/20221202/j6p8kb034039.png',
      msg_type: 1,
      name: userData.nickname.value ?? '未知用户',
      content: message?.text ?? '',
      publisher: param.publisher,
      timestamp: new Date(param.timestamp),
      istoday: true,
    };
    this.messageMapList[param.channelName].push(data);
    this.pageFun?.();
  }

  async saveMeesage(parse: {
    from_id: string;
    from_username: string;
    target_id: string;
    // target_name: string;
    channel: string;
    content: Object;
  }) {
    console.log(parse);
    let obj = Parse.Object.extend('MessageLog');
    let message = new obj();
    message.set('from_id', parse.from_id);
    message.set('from_username', parse.from_username);
    message.set('target_id', parse.target_id);
    // message.set('target_name', parse.target_name);
    message.set('channel', parse.channel);
    message.set('content', parse.content);
    message.set('company', {
      __type: 'Pointer',
      className: 'Company',
      objectId: this.company,
    });
    await message.save();
  }

  async getUserMetadata(uid: string) {
    try {
      const result = await this.rtmClient?.storage.getUserMetadata({
        userId: uid,
      });
      return result.metadata;
    } catch (status) {
      console.log(JSON.stringify(status));
    }
  }

  async publishMessage(
    message: string,
    channelName: string,
    channelType?: string
  ) {
    const payload = { type: 'text', text: message };
    const publishMessage = JSON.stringify(payload);
    const publishOptions = { channelType: channelType ?? 'MESSAGE' };
    try {
      const result = await this.rtmClient?.publish(
        channelName,
        publishMessage,
        publishOptions
      );
      console.log(result);
    } catch (status) {
      console.log(status);
    }
  }
}
