import { expect, test, mock, beforeEach, afterEach } from 'bun:test';
import { handleCommands } from './handle-commands';
import { CommandInteraction, Constants, ModalSubmitInteraction, type ApplicationCommandStructure } from '@projectdysnomia/dysnomia';
import type { CommandHandler } from '../../dist';

let commands: Record<string, CommandHandler<ApplicationCommandStructure>>;

beforeEach(() => {
  commands = {};
});

afterEach(() => {
  commands = {};
});

mock.module('./command-helpers', () => ({
  getCommandName: () => 'testCommand',
}));

test('handleCommands executes command when interaction is CommandInteraction and command exists', async () => {
  const mockExecute = mock(() => Promise.resolve());
  const mockCommand = { definition: { name: 'testCommand' } as any, execute: mockExecute };
  commands['testCommand'] = mockCommand;

  const mockInteraction = {
    type: Constants.InteractionTypes.APPLICATION_COMMAND,
    data: { name: 'testCommand' },
  } as any;
  Object.setPrototypeOf(mockInteraction, CommandInteraction.prototype);

  handleCommands(mockInteraction, commands, {} as any);

  expect(mockExecute).toHaveBeenCalledWith(mockInteraction, expect.any(Object));
});

test('handleCommands executes command when interaction is CommandInteraction and command exists', async () => {
  const mockExecute = mock(() => Promise.resolve());
  const mockCommand = { definition: { name: 'testCommand' } as any, execute: mockExecute };
  commands['testCommand'] = mockCommand;

  const mockInteraction = {
    type: Constants.InteractionTypes.MODAL_SUBMIT,
    data: { name: 'testCommand' },
  } as any;
  Object.setPrototypeOf(mockInteraction, ModalSubmitInteraction.prototype);

  handleCommands(mockInteraction, commands, {} as any);

  expect(mockExecute).toHaveBeenCalledWith(mockInteraction, expect.any(Object));
});

test('handleCommands does nothing when interaction not a CommandInteraction, ModalSubmitInteraction, MessageComponentInteraction, or AutoCompleteInteraction', () => {
  const mockInteraction = {
    instanceof: (cls: any) => false,
  } as any;

  // Should not throw or do anything
  expect(() => handleCommands(mockInteraction, commands, {} as any)).not.toThrow();
});
