import { DataSource } from 'typeorm';
import { RoomEntity } from '../../../entities';
import { replaceRoomRelations } from '../../relations';
import { UpdateRoomCommand } from '../../types';
import {
  applyUpdates,
  boolToInt,
  TransformMap
} from './utils/applyUpdates';
import { getCurrentUserScope, userOwnsRoom } from '../../current-user-scope';

const ROOM_TRANSFORMS: TransformMap = {
  hasPassword: boolToInt,
  isPrivate: boolToInt,
  userCount: (val) => (val ?? 0)
};

function extractSlowModeInterval(updates: UpdateRoomCommand['payload']['updates']): number | undefined {
  if (typeof updates.slowModeInterval === 'number' && Number.isFinite(updates.slowModeInterval)) {
    return updates.slowModeInterval;
  }

  const permissions = updates.permissions && typeof updates.permissions === 'object'
    ? updates.permissions as { slowModeInterval?: unknown }
    : null;

  return typeof permissions?.slowModeInterval === 'number' && Number.isFinite(permissions.slowModeInterval)
    ? permissions.slowModeInterval
    : undefined;
}

export async function handleUpdateRoom(command: UpdateRoomCommand, dataSource: DataSource): Promise<void> {
  const { roomId, updates } = command.payload;

  await dataSource.transaction(async (manager) => {
    const currentUserId = await getCurrentUserScope(manager);

    if (!await userOwnsRoom(manager, roomId, currentUserId)) {
      return;
    }

    const repo = manager.getRepository(RoomEntity);
    const existing = await repo.findOne({ where: { id: roomId } });

    if (!existing)
      return;

    const {
      channels,
      members,
      roles,
      roleAssignments,
      channelPermissions,
      permissions: rawPermissions,
      ...entityUpdates
    } = updates;
    const slowModeInterval = extractSlowModeInterval(updates);

    if (slowModeInterval !== undefined) {
      entityUpdates.slowModeInterval = slowModeInterval;
    }

    applyUpdates(existing, entityUpdates, ROOM_TRANSFORMS);
    await repo.save(existing);
    await replaceRoomRelations(manager, roomId, {
      channels,
      members,
      roles,
      roleAssignments,
      channelPermissions,
      permissions: rawPermissions
    });
  });
}

