import { Entity } from '@acrd/types';
import DBWrapper from './db-wrapper';
import { Channel, ChannelDocument, TextChannelDocument, VoiceChannelDocument } from './models/channel';
import { generateSnowflake } from './snowflake-entity';

export default class Channels extends DBWrapper<string, ChannelDocument> {
  public async get(id: string | undefined) {
    const channel = await Channel.findById(id);
    if (!channel)
      throw new TypeError('Channel not found');
    return channel;
  }

  public async getDM(id: string | undefined) {
    return await this.get(id) as DMChannelDocument;
  }
  public async getText(id: string | undefined) {
    return await this.get(id) as TextChannelDocument;
  }
  public async getVoice(id: string | undefined) {
    return await this.get(id) as VoiceChannelDocument;
  }

  public async create(options: Partial<Entity.Channel>): Promise<ChannelDocument> {
    const isVoice = options.type === 'VOICE';
    return Channel.create({
      _id: options.id ?? generateSnowflake(),
      name: options.name || (isVoice ? 'Voice Channel' : 'chat'),
      position: await Channel.countDocuments({ guildId: options.guildId }),
      type: options.type || 'TEXT',
      userIds: isVoice ? [] : undefined,
      ...options as any,
    });
  }

  public async createDM(userIds: string[]) {
    return this.create({ userIds, type: 'DM' }) as Promise<DMChannelDocument>;
  }
  
  public async createText(guildId: string, name?: string) {
    return this.create({ 
      guildId, 
      type: 'TEXT',
      name: name || 'chat' 
    }) as Promise<TextChannelDocument>;
  }
  
  public async createVoice(guildId: string, name?: string) {
    return this.create({ 
      guildId, 
      type: 'VOICE',
      name: name || 'Voice Channel',
      userIds: [] 
    }) as Promise<VoiceChannelDocument>;
  }

  public async joinVC(channel: VoiceChannelDocument, userId: string) {
    if (!channel.userIds) channel.userIds = [];
    channel.userIds.push(userId);
    return await channel.save();
  }

  public async leaveVC(channel: VoiceChannelDocument, userId: string) {
    if (!channel.userIds) return channel;
    const index = channel.userIds.indexOf(userId);
    if (index > -1) channel.userIds.splice(index, 1);
    return await channel.save();
  }

  public async getSystem(guildId: string) {
    return await Channel.findOne({ guildId, type: 'TEXT' });
  }
}