import {Expense} from '../database/expense.js';
import {RouteError} from '../routes/routeError.js';
import {calculate} from './calculateSettlements.js';

export class ManageGroup {
  #groupName;
  #db;

  constructor(groupName, db) {
    this.#groupName = groupName;
    this.#db = db;
  }

  async getGroup() {
    return await this.#db.getGroup(this.#groupName);
  }

  async assertPermissionOf(userName) {
    const members = await this.#db.getUsersOfGroup(await this.getGroup());
    if (!members.find(member => member.name === userName)) throw new RouteError(401, 'You are not a member of the group');
  }

  async getUsersOfGroup() {
    return await this.#db.getUsersOfGroup(await this.getGroup());
  }

  async getExpensesOfGroup() {
    return await this.#db.getExpensesOfGroup(await this.getGroup());
  }

  async closeGroup() {
    await this.#db.closeGroup(await this.getGroup());
  }

  async getSettlements() {
    const group = await this.getGroup();
    if (!group.closed) throw new RouteError(400, 'Group not closed');

    return await calculate(await this.getUsersOfGroup(), await this.getExpensesOfGroup());
  }

  async addUser(username) {
    const group = await this.getGroup();
    if (group.closed) throw new RouteError(400, 'Group closed');

    const userToAdd = await this.#db.getUser(username);
    if (!userToAdd) throw new RouteError(400, 'No such user');

    const members = await this.#db.getUsersOfGroup(group);

    if (members.find(member => member.name === username)) {
      throw new RouteError(400, 'User is already a member of this group');
    }

    await this.#db.addUserToGroup(userToAdd, group);
  }

  async addExpense(creator, description, amount) {
    const group = await this.getGroup();
    if (group.closed) throw new RouteError(400, 'Group closed');

    await this.#db.createExpense(new Expense(
        group,
        creator,
        description,
        amount
    ));
  }

  async deleteExpense(id) {
    if ((await this.getGroup()).closed) throw new RouteError(400, 'Group closed');
    await this.#db.deleteExpense(id);
  }
}