// Copyright (c) 2020-2021 Drew Lemmy
// This file is part of TenebraWeb 2 under AGPL-3.0.
// Full details: https://github.com/tmpim/TenebraWeb2/blob/master/LICENSE.txt
import * as actions from "@actions/ContactsActions";
import { createReducer } from "typesafe-actions";

import {
  Contact, ContactMap, loadContacts, CONTACT_UPDATABLE_KEYS
} from "@contacts";

export interface State {
  readonly contacts: ContactMap;
}

export function getInitialContactsState(): State {
  const contacts = loadContacts();
  return { contacts };
}

function assignNewContactProperties(
  state: State,
  id: string,
  partialContact: Partial<Contact>,
  allowedKeys?: (keyof Contact)[]
) {
  // Fetch the old contact and assign the new properties
  const { [id]: contact } = state.contacts;
  const newContact = allowedKeys
    ? allowedKeys.reduce((o, key) => partialContact[key] !== undefined
      ? { ...o, [key]: partialContact[key] }
      : o, {})
    : partialContact;

  return {
    ...state,
    contacts: {
      ...state.contacts,
      [id]: { ...contact, ...newContact }
    }
  };
}

export const ContactsReducer = createReducer({ contacts: {} } as State)
  // Load contacts
  .handleAction(actions.loadContacts, (state, { payload }) => ({
    ...state,
    contacts: {
      ...state.contacts,
      ...payload
    }
  }))
  // Add contact
  .handleAction(actions.addContact, (state, { payload }) => ({
    ...state,
    contacts: {
      ...state.contacts,
      [payload.id]: payload
    }
  }))
  // Remove contact
  .handleAction(actions.removeContact, (state, { payload }) => {
    // Get the contacts without the one we want to remove
    const { [payload]: _, ...contacts } = state.contacts;
    return { ...state, contacts };
  })
  // Update contact
  .handleAction(actions.updateContact, (state, { payload }) =>
    assignNewContactProperties(state, payload.id, payload.contact, CONTACT_UPDATABLE_KEYS));
