import { AbstractMethods } from "../abstract.method";
import { IgApiClient, PostingAlbumOptions, PostingPhotoOptions, PostingStoryPhotoOptions, PostingStoryVideoOptions, PostingVideoOptions } from '../../utils/plugins/bot-intagram';
import { get } from 'request-promise';

export class SocialNetworkInstagramsMethods extends AbstractMethods {
  constructor(model) {
    super(model);
  }
  async startProvider(body) {
    const ig = new IgApiClient();
    ig.state.generateDevice(body.username);
    ig.request.end$.subscribe(async () => {
      const serialized = await ig.state.serialize();
      delete serialized.constants;
      await this.saveSession(body.username, { username: body.username, provider_id: body.provider_id, session: serialized });
    });
    const loggedInUser = await ig.account.login(body.username, body.password);
    process.nextTick(async () => await ig.simulate.postLoginFlow());
    return loggedInUser;
  }
  async saveSession(username: string, session: { username: string, provider_id: string, session: any }) {
    try {
      return await this.model.updateOne({ username }, { username, session }, { upsert: true });
    } catch (error) {
      throw error;
    }
  }
  async loadSession(username) {
    try {
      const sessionData = await this.model.findOne({ username })
      if (sessionData) {
        const ig = new IgApiClient();
        await ig.state.deserialize(JSON.stringify(sessionData.session.session));
        return ig;
      } else {
        throw 'SESSION_NOT_FOUND';
      }
    } catch (error) {
      throw error;
    }
  }
  async deleteSession(username) {
    try {
      return await this.model.deleteOne({ username })
    } catch (error) {
      throw error;
    }
  }
  async sendMessages(ctx, list: { username: string; message: string }[]) {
    return new Promise(async (resolve, reject) => {
      try {
        const listPromises = list.map((item) => {
          return new Promise((resol, rejc) => {
            ctx.user.getIdByUsername(item.username).then((userId) => {
              console.log(item.username, userId, item.message)
              const thread = ctx.entity.directThread([userId.toString()]); // DirectThreadEntity direct-thread.entity.ts
              resol(thread.broadcastText(item.message))
            }).catch((error) => {
              console.log('error', error);
              rejc(error)
            });
          })
        });
        const responses = await Promise.allSettled(listPromises);
        setTimeout(() => {
          resolve(responses);
        }, 500);

      } catch (error) {
        console.log('error 2', error);
        reject(error);
      }
    });
  }
  async sendPhotos(ctx, list: { username: string; url: string }[]) {
    return new Promise(async (resolve, reject) => {
      try {
        const imageBuffer = await get({
          url: list[0].url,
          encoding: null
        })
        const listPromises = list.map((item) => {
          return new Promise((resol, rejc) => {
            ctx.user.getIdByUsername(item.username).then((userId) => {
              const thread = ctx.entity.directThread([userId.toString()]); // DirectThreadEntity direct-thread.entity.ts
              resol(thread.broadcastPhoto({ file: imageBuffer }))
            }).catch((error) => {
              console.log('error', error);
              rejc(error)
            });
          })
        });
        const responses = await Promise.allSettled(listPromises);
        setTimeout(() => {
          resolve(responses);
        }, 500);
      } catch (error) {
        console.log('error 2', error);
        reject(error);
      }
    });
  }
  async sendVideos(ctx, list: { username: string; url: string }[]) {
    return new Promise(async (resolve, reject) => {
      try {
        const videoBuffer = await get({
          url: list[0].url,
          encoding: null
        })
        const listPromises = list.map((item) => {
          return new Promise((resol, rejc) => {
            ctx.user.getIdByUsername(item.username).then((userId) => {
              const thread = ctx.entity.directThread([userId.toString()]); // DirectThreadEntity direct-thread.entity.ts
              resol(thread.broadcastVideo({ video: videoBuffer }))
            }).catch((error) => {
              console.log('error', error);
              rejc(error)
            });
          })
        });
        const responses = await Promise.allSettled(listPromises);
        setTimeout(() => {
          resolve(responses);
        }, 500);

      } catch (error) {
        console.log('error 2', error);
        reject(error);
      }
    });
  }
  async sendVoices(ctx, list: { username: string; url: string }[]) {
    return new Promise(async (resolve, reject) => {
      try {
        const audioBuffer = await get({
          url: list[0].url,
          encoding: null
        })
        const listPromises = list.map((item) => {
          return new Promise((resol, rejc) => {
            ctx.user.getIdByUsername(item.username).then((userId) => {
              const thread = ctx.entity.directThread([userId.toString()]); // DirectThreadEntity direct-thread.entity.ts
              resol(thread.broadcastVoice({ file: audioBuffer }))
            }).catch((error) => {
              console.log('error', error);
              rejc(error)
            });
          })
        });
        const responses = await Promise.allSettled(listPromises);
        setTimeout(() => {
          resolve(responses);
        }, 500);

      } catch (error) {
        console.log('error 2', error);
        reject(error);
      }
    });
  }
  async sendStories(ctx, list: { username: string; url: string; url_cover?: string }[]) {
    return new Promise(async (resolve, reject) => {
      try {
        const fileBuffer = await get({
          url: list[0].url,
          encoding: null
        })
        let coverBuffer;
        if (list[0].url_cover) {
          coverBuffer = await get({
            url: list[0].url_cover,
            encoding: null
          })
        }
        const listPromises = list.map((item) => {
          return new Promise((resol, rejc) => {
            if (!item.url_cover) {
              ctx.user.getIdByUsername(item.username).then((userId) => {
                const thread = ctx.entity.directThread([userId.toString()]); // DirectThreadEntity direct-thread.entity.ts
                resol(thread.broadcastStory({
                  file: fileBuffer,
                  viewMode: 'replayable',
                  replyType: 'story'
                }));
              }).catch((error) => {
                console.log('error', error);
                rejc(error)
              });
            } else {
              ctx.user.getIdByUsername(item.username).then((userId) => {
                const thread = ctx.entity.directThread([userId.toString()]); // DirectThreadEntity direct-thread.entity.ts
                resol(thread.broadcastStory({
                  video: fileBuffer,
                  coverImage: coverBuffer,
                  replyType: 'story',
                  viewMode: 'replayable',
                }));
              }).catch((error) => {
                console.log('error', error);
                rejc(error)
              });
            }
          })
        });
        const responses = await Promise.allSettled(listPromises);
        setTimeout(() => {
          resolve(responses);
        }, 500);

      } catch (error) {
        console.log('error 2', error);
        reject(error);
      }
    });
  }
  async publishPhoto(ctx, list: { url: string; caption: string }[]) {
    return new Promise(async (resolve, reject) => {
      try {
        const listPromises = list.map((item) => {
          return new Promise(async (resol, rejc) => {
            try {
              const imageBuffer = await get({
                url: item.url,
                encoding: null
              })
              resol(ctx.publish.photo({
                file: imageBuffer,
                caption: item.caption,
              }))
            } catch (error) {
              rejc(error)
            }
          })
        });
        const responses = await Promise.allSettled(listPromises);
        setTimeout(() => {
          resolve(responses);
        }, 500);
      } catch (error) {
        console.log('error 2', error);
        reject(error);
      }
    });
  }
  async publishVideo(ctx, list: { url: string; caption: string; url_cover: string }[]) {
    return new Promise(async (resolve, reject) => {
      try {
        const listPromises = list.map((item) => {
          return new Promise(async (resol, rejc) => {
            try {
              const videoBuffer = await get({
                url: item.url,
                encoding: null
              })
              let coverBuffer;
              if (coverBuffer) {
                coverBuffer = await get({
                  url: list[0].url_cover,
                  encoding: null
                })
              }
              resol(ctx.publish.video({
                video: videoBuffer,
                coverImage: coverBuffer,
                caption: item.caption,
              }))
            } catch (error) {
              rejc(error)
            }
          }).catch((error) => {
            reject(error);
          })
        })
        const responses = await Promise.allSettled(listPromises);
        setTimeout(() => {
          resolve(responses);
        }, 500);
      } catch (error) {
        console.log('error 2', error);
        reject(error);
      }
    });
  }
  async publishAlbum(ctx, list: { url: string; caption: string; url_cover?: string }[]) {
    return new Promise(async (resolve, reject) => {
      try {
        const listPromises = list.map((item) => {
          return new Promise(async (resol, rejc) => {
            get({
              url: item.url,
              encoding: null
            }).then((fileBuffer) => {
              if (item.url_cover) {
                get({
                  url: item.url_cover,
                  encoding: null
                }).then((coverBuffer) => {
                  resol({
                    video: fileBuffer,
                    coverImage: coverBuffer,
                  })
                }).catch((error) => {
                  rejc(error);
                })
              } else {
                resol({
                  file: fileBuffer
                })
              }
            }).catch((error) => {
              rejc(error);
            })

          }).catch((error) => {
            reject(error);
          })
        })
        const items = await Promise.allSettled(listPromises);
        console.log(items)
        const responses = await ctx.publish.album({
          items: [...items].map((item: any) => item.value),
          caption: list[0].caption,
        })
        setTimeout(() => {
          resolve(responses);
        }, 500);
      } catch (error) {
        console.log('error 2', error);
        reject(error);
      }
    });
  }
  async publishStory(ctx, list: { url: string; url_cover?: string; }[]) {
    return new Promise(async (resolve, reject) => {
      try {
        const listPromises = list.map((item) => {
          return new Promise(async (resol, rejc) => {
            const fileBuffer = await get({
              url: item.url,
              encoding: null
            })
            try {
              if (item.url_cover) {
                const coverBuffer = await get({
                  url: item.url_cover,
                  encoding: null
                })
                resol(ctx.publish.story({
                  video: fileBuffer,
                  coverImage: coverBuffer,
                }))
              } else {
                resol(ctx.publish.story({
                  file: fileBuffer,
                }))
              }
            } catch (error) {
              rejc(error)
            }
          }).catch((error) => {
            reject(error);
          })
        })
        const responses = await Promise.allSettled(listPromises);
        setTimeout(() => {
          resolve(responses);
        }, 500);
      } catch (error) {
        console.log('error 2', error);
        reject(error);
      }
    });
  }
  async sendLinks(ctx, list: { username: string; message: string }[]) {
    return new Promise(async (resolve, reject) => {
      try {
        const listPromises = list.map((item) => {
          return new Promise((resol, rejc) => {
            ctx.user.getIdByUsername(item.username).then((userId) => {
              console.log(item.username, userId, item.message)
              const thread = ctx.entity.directThread([userId.toString()]); // DirectThreadEntity direct-thread.entity.ts
              resol(thread.broadcastLink(item.message))
            }).catch((error) => {
              console.log('error', error);
              rejc(error)
            });
          })
        });
        const responses = await Promise.allSettled(listPromises);
        setTimeout(() => {
          resolve(responses);
        }, 500);

      } catch (error) {
        console.log('error 2', error);
        reject(error);
      }
    });
  }
  async sendProfiles(ctx, list: { username: string; message: string }[]) {
    return new Promise(async (resolve, reject) => {
      try {
        const listPromises = list.map((item) => {
          return new Promise((resol, rejc) => {
            ctx.user.getIdByUsername(item.username).then((userId) => {
              console.log(item.username, userId, item.message)
              const thread = ctx.entity.directThread([userId.toString()]); // DirectThreadEntity direct-thread.entity.ts
              resol(thread.broadcastProfile(item.message))
            }).catch((error) => {
              console.log('error', error);
              rejc(error)
            });
          })
        });
        const responses = await Promise.allSettled(listPromises);
        setTimeout(() => {
          resolve(responses);
        }, 500);

      } catch (error) {
        console.log('error 2', error);
        reject(error);
      }
    });
  }
  async sendReels(ctx, list: { username: string; message: string }[]) {
    return new Promise(async (resolve, reject) => {
      try {
        const listPromises = list.map((item) => {
          return new Promise((resol, rejc) => {
            ctx.user.getIdByUsername(item.username).then((userId) => {
              console.log(item.username, userId, item.message)
              const thread = ctx.entity.directThread([userId.toString()]); // DirectThreadEntity direct-thread.entity.ts
              resol(thread.broadcastReel(item.message))
            }).catch((error) => {
              console.log('error', error);
              rejc(error)
            });
          })
        });
        const responses = await Promise.allSettled(listPromises);
        setTimeout(() => {
          resolve(responses);
        }, 500);

      } catch (error) {
        console.log('error 2', error);
        reject(error);
      }
    });
  }
  async sendUserStories(ctx, list: { username: string; message: string }[]) {
    return new Promise(async (resolve, reject) => {
      try {
        const listPromises = list.map((item) => {
          return new Promise((resol, rejc) => {
            ctx.user.getIdByUsername(item.username).then((userId) => {
              console.log(item.username, userId, item.message)
              const thread = ctx.entity.directThread([userId.toString()]); // DirectThreadEntity direct-thread.entity.ts
              resol(thread.broadcastUserStory(item.message))
            }).catch((error) => {
              console.log('error', error);
              rejc(error)
            });
          })
        });
        const responses = await Promise.allSettled(listPromises);
        setTimeout(() => {
          resolve(responses);
        }, 500);

      } catch (error) {
        console.log('error 2', error);
        reject(error);
      }
    });
  }
  async sendPosts(ctx, list: { username: string; message: string }[]) {
    return new Promise(async (resolve, reject) => {
      try {
        const listPromises = list.map((item) => {
          return new Promise((resol, rejc) => {
            ctx.user.getIdByUsername(item.username).then((userId) => {
              console.log(item.username, userId, item.message)
              const thread = ctx.entity.directThread([userId.toString()]); // DirectThreadEntity direct-thread.entity.ts
              resol(thread.broadcastPost(item.message))
            }).catch((error) => {
              console.log('error', error);
              rejc(error)
            });
          })
        });
        const responses = await Promise.allSettled(listPromises);
        setTimeout(() => {
          resolve(responses);
        }, 500);

      } catch (error) {
        console.log('error 2', error);
        reject(error);
      }
    });
  }
}
