import {
  Constants,
  type ActionRow,
  type Button,
  type ChannelSelectMenu,
  type GuildChannelTypes,
  type MentionableSelectMenu,
  type PartialEmoji,
  type RoleSelectMenu,
  type StringSelectMenu,
  type TextInput,
  type UserSelectMenu,
  type LabelComponent,
  type ContainerComponent,
  type TextDisplayComponent,
  type SectionComponent,
  type MediaGalleryComponent,
  type SeparatorComponent,
  type FileComponent,
  type InteractionButton,
  type URLButton,
  type PremiumButton,
  type ThumbnailComponent,
} from '@projectdysnomia/dysnomia';

export type ActionRowItem = Button | StringSelectMenu | UserSelectMenu | RoleSelectMenu | MentionableSelectMenu | ChannelSelectMenu;
export const createActionRow = (...components: ActionRowItem[]): ActionRow => ({
  type: Constants.ComponentTypes.ACTION_ROW,
  components,
});

export enum ButtonStyle {
  PRIMARY = 1,
  SECONDARY = 2,
  SUCCESS = 3,
  DANGER = 4,
}

export interface ButtonOptions {
  style?: ButtonStyle;
  emoji?: PartialEmoji;
  disabled?: boolean;
}

export const createButton = (label: string, custom_id: string, options?: ButtonOptions): InteractionButton => ({
  type: Constants.ComponentTypes.BUTTON,
  style: options?.style ?? Constants.ButtonStyles.PRIMARY,
  label,
  custom_id,
  ...options,
});

export interface URLButtonOptions {
  emoji?: PartialEmoji;
  disabled?: boolean;
}

export const createURLButton = (label: string, url: string, options?: URLButtonOptions): URLButton => ({
  type: Constants.ComponentTypes.BUTTON,
  style: Constants.ButtonStyles.LINK,
  label,
  url,
  ...options,
});

export interface PremiumButtonOptions {
  emoji?: PartialEmoji;
  disabled?: boolean;
}

export const createPremiumButton = (sku_id: string, options?: PremiumButtonOptions): PremiumButton => ({
  type: Constants.ComponentTypes.BUTTON,
  style: Constants.ButtonStyles.PREMIUM,
  sku_id,
  ...options,
});

export interface StringSelectOpts {
  placeholder?: string;
  min_values?: number;
  max_values?: number;
  disabled?: boolean;
  required?: boolean; // Note: not actually a property of StringSelectMenu, but useful for modals
}

export interface StringSelectOption {
  label: string;
  value: string;
  description?: string;
  emoji?: {
    name?: string;
    id?: string;
    animated?: boolean;
  };
  default?: boolean;
}

export const createStringSelect = (
  custom_id: string,
  selectOpts: StringSelectOpts,
  ...options: StringSelectOption[]
): StringSelectMenu => ({
  type: Constants.ComponentTypes.STRING_SELECT,
  custom_id,
  options,
  placeholder: selectOpts.placeholder ?? '',
  min_values: selectOpts.min_values ?? 1,
  max_values: selectOpts.max_values ?? 1,
  disabled: selectOpts.disabled ?? false,
  required: selectOpts.required ?? false, // Note: not actually a property of StringSelectMenu, but useful for modals
});

export interface TextInputOptions {
  isParagraph?: boolean;
  label?: string;
  min_length?: number;
  max_length?: number;
  required?: boolean;
  value?: string;
  placeholder?: string;
}

export const createTextInput = (custom_id: string, options?: TextInputOptions): TextInput => ({
  type: Constants.ComponentTypes.TEXT_INPUT,
  custom_id,
  style: options.isParagraph ? Constants.TextInputStyles.PARAGRAPH : Constants.TextInputStyles.SHORT,
  label: options?.label ?? '',
  min_length: options?.min_length ?? 0,
  max_length: options?.max_length ?? 4000,
  required: options?.required ?? false,
  value: options?.value ?? '',
  placeholder: options?.placeholder ?? '',
});

export interface UserSelectOptions {
  placeholder?: string;
  min_values?: number;
  max_values?: number;
  disabled?: boolean;
  default_values?: Array<{ id: string; type: 'user' }>;
}

export const createUserSelect = (custom_id: string, options?: UserSelectOptions): UserSelectMenu => ({
  type: Constants.ComponentTypes.USER_SELECT,
  custom_id,
  placeholder: options?.placeholder ?? '',
  min_values: options?.min_values ?? 1,
  max_values: options?.max_values ?? 1,
  disabled: options?.disabled ?? false,
  default_values: options?.default_values ?? [],
});

export interface RoleSelectOptions {
  placeholder?: string;
  min_values?: number;
  max_values?: number;
  disabled?: boolean;
  default_values?: Array<{ id: string; type: 'role' }>;
}

export const createRoleSelect = (custom_id: string, options?: RoleSelectOptions): RoleSelectMenu => ({
  type: Constants.ComponentTypes.ROLE_SELECT,
  custom_id,
  placeholder: options?.placeholder ?? '',
  min_values: options?.min_values ?? 1,
  max_values: options?.max_values ?? 1,
  disabled: options?.disabled ?? false,
  default_values: options?.default_values ?? [],
});

export interface MentionableSelectOptions {
  placeholder?: string;
  min_values?: number;
  max_values?: number;
  disabled?: boolean;
  default_values?: Array<{ id: string; type: 'user' | 'role' }>;
}

export const createMentionableSelect = (custom_id: string, options?: MentionableSelectOptions): MentionableSelectMenu => ({
  type: Constants.ComponentTypes.MENTIONABLE_SELECT,
  custom_id,
  placeholder: options?.placeholder ?? '',
  min_values: options?.min_values ?? 1,
  max_values: options?.max_values ?? 1,
  disabled: options?.disabled ?? false,
  default_values: options?.default_values ?? [],
});

export interface ChannelSelectOptions {
  channel_types?: GuildChannelTypes[];
  placeholder?: string;
  min_values?: number;
  max_values?: number;
  disabled?: boolean;
  default_values?: Array<{ id: string; type: 'channel' }>;
}

export const createChannelSelect = (custom_id: string, options?: ChannelSelectOptions): ChannelSelectMenu => ({
  type: Constants.ComponentTypes.CHANNEL_SELECT,
  custom_id,
  channel_types: options?.channel_types ?? [],
  placeholder: options?.placeholder ?? '',
  min_values: options?.min_values ?? 1,
  max_values: options?.max_values ?? 1,
  disabled: options?.disabled ?? false,
  default_values: options?.default_values ?? [],
});

export interface SectionOptions {
  components: Array<TextDisplayComponent>;
  accessory: Button | ThumbnailComponent;
}

export const createSection = (accessory: Button | ThumbnailComponent, ...components: Array<TextDisplayComponent>): SectionComponent => ({
  type: Constants.ComponentTypes.SECTION,
  accessory,
  components,
});

/**
 * Creates a text display component where the text will be displayed similar to a message: supports markdown
 * @param content The text content to display.
 * @returns The created text display component.
 */
export const createTextDisplay = (content: string) => ({
  type: Constants.ComponentTypes.TEXT_DISPLAY,
  content,
});

export interface ThumbnailOptions {
  media: {
    url: string; // Supports arbitrary urls and attachment://<filename> references
  };
  description?: string;
  spoiler?: boolean;
}

export const createThumbnail = (url: string, description?: string, spoiler?: boolean): ThumbnailComponent => ({
  type: Constants.ComponentTypes.THUMBNAIL,
  media: {
    url,
  },
  description,
  spoiler,
});

export interface MediaItem {
  url: string; // Supports arbitrary urls and attachment://<filename> references
  description?: string;
  spoiler?: boolean;
}

export const createMediaGallery = (...items: MediaItem[]): MediaGalleryComponent => ({
  type: Constants.ComponentTypes.MEDIA_GALLERY,
  items: items.map((item) => ({
    type: Constants.ComponentTypes.FILE,
    media: { url: item.url },
    description: item.description,
    spoiler: item.spoiler,
  })),
});

export interface FileOptions {
  url: string; // Supports only attachment://<filename> references
  spoiler?: boolean;
}

export const createFile = (url: string, spoiler?: boolean): FileComponent => ({
  type: Constants.ComponentTypes.FILE,
  file: {
    url,
  },
  spoiler,
});

export enum Padding {
  SMALL = 1,
  LARGE = 2,
}

export interface SeparatorOptions {
  divider?: boolean;
  spacing?: Padding;
}
export const createSeparator = (spacing?: Padding, divider?: boolean): SeparatorComponent => ({
  type: Constants.ComponentTypes.SEPARATOR,
  divider,
  spacing: spacing ?? Padding.SMALL,
});

export interface ContainerOptions {
  accent_color?: number;
  spoiler?: boolean;
}

export type ContainerItems =
  | ActionRow
  | TextDisplayComponent
  | SectionComponent
  | MediaGalleryComponent
  | SeparatorComponent
  | FileComponent;

export const createContainer = (options: ContainerOptions, ...components: ContainerItems[]): ContainerComponent => ({
  type: Constants.ComponentTypes.CONTAINER,
  ...options,
  components,
});

export const createModalLabel = (label: string, component: TextInput | StringSelectMenu): LabelComponent => ({
  type: Constants.ComponentTypes.LABEL,
  label,
  component,
});
