import { CommandInteraction, Guild, GuildMember, User, TextChannel, Client, Collection, SnowflakeUtil } from 'discord.js';

export class MockDiscord {
  public client: Client;
  public guild: Guild;
  public channel: TextChannel;
  public user: User;
  public member: GuildMember;

  constructor() {
    this.client = new Client({ intents: [] });

    // Mock User
    this.user = {
      id: SnowflakeUtil.generate().toString(),
      bot: false,
      username: 'TestUser',
      discriminator: '1234',
      displayAvatarURL: jest.fn().mockReturnValue('avatar_url'),
    } as unknown as User;

    // Mock Guild
    this.guild = {
      id: SnowflakeUtil.generate().toString(),
      name: 'Test Guild',
      client: this.client,
      members: {
        cache: new Collection(),
        fetch: jest.fn(),
      },
      channels: {
        cache: new Collection(),
      },
    } as unknown as Guild;

    // Mock Member
    this.member = {
      id: this.user.id,
      user: this.user,
      guild: this.guild,
      roles: {
        cache: new Collection(),
        add: jest.fn(),
        remove: jest.fn(),
      },
      permissions: {
        has: jest.fn().mockReturnValue(true),
      },
    } as unknown as GuildMember;

    (this.guild.members.cache as Collection<string, GuildMember>).set(this.member.id, this.member);

    // Mock Channel
    this.channel = {
      id: SnowflakeUtil.generate().toString(),
      name: 'general',
      guild: this.guild,
      isTextBased: jest.fn().mockReturnValue(true),
      send: jest.fn(),
    } as unknown as TextChannel;
  }

  public createMockInteraction(commandName: string, options: any = {}): CommandInteraction {
    const interaction: any = {
      id: SnowflakeUtil.generate().toString(),
      applicationId: '1234567890',
      type: 2, // ApplicationCommand
      commandName,
      user: this.user,
      member: this.member,
      guild: this.guild,
      channel: this.channel,
      deferred: false,
      replied: false,
      options: {
        getString: jest.fn((name) => options[name] ?? null),
        getInteger: jest.fn((name) => options[name] ?? null),
        getBoolean: jest.fn((name) => options[name] ?? null),
        getUser: jest.fn((name) => options[name] ?? null),
        getMember: jest.fn((name) => options[name] ?? null),
      },
      deferReply: jest.fn(async () => {
        interaction.deferred = true;
      }),
      reply: jest.fn(async () => {
        interaction.replied = true;
      }),
      editReply: jest.fn(async () => {}),
      followUp: jest.fn(async () => {}),
      isCommand: jest.fn(() => true),
    };

    return interaction as CommandInteraction;
  }
}
