
import { ROLES, API_ORIGIN } from '../constants.js';
import { fetcher } from '@cloudron/pankow';

const changeHandlers = {};
const KEYS = {
  AVATAR: 'avatar',         // only returns a URI with cachebusting
};

function notifyChange(key, value) {
  const listener = changeHandlers[key] || [];
  listener.forEach(h => h(value));
}

// key is one of KEYS
function onChange(key, handler) {
  if (typeof handler !== 'function') return;

  if (!changeHandlers[key]) changeHandlers[key] = [];

  changeHandlers[key].push(handler);
}

function create() {
  const accessToken = localStorage.token;

  // we use that currently only to generate the avatarUrl for the change handler
  let profileCached = null;

  return {
    name: 'ProfileModel',
    async logout() {
      // attempt to destroy oidc session in the spirit of true SSO
      // eslint-disable-next-line no-empty, no-unused-vars
      try { await fetcher.del(`${API_ORIGIN}/api/v1/profile/sessions`, null, { access_token: accessToken }); } catch (e) {}

      localStorage.removeItem('token');

      window.location.href = '/';
    },
    async get() {
      let error, result;
      try {
        result = await fetcher.get(`${API_ORIGIN}/api/v1/profile`, { access_token: accessToken });
      } catch (e) {
        error = e;
      }

      if (error || result.status !== 200) return [error || result];

      result.body.isAtLeastUserManager = [ ROLES.OWNER, ROLES.ADMIN, ROLES.MAIL_MANAGER, ROLES.USER_MANAGER ].indexOf(result.body.role) !== -1;
      result.body.isAtLeastMailManager = [ ROLES.OWNER, ROLES.ADMIN, ROLES.MAIL_MANAGER ].indexOf(result.body.role) !== -1;
      result.body.isAtLeastAdmin = [ ROLES.OWNER, ROLES.ADMIN ].indexOf(result.body.role) !== -1;
      result.body.isAtLeastOwner = [ ROLES.OWNER ].indexOf(result.body.role) !== -1;

      result.body.backgroundImageUrl = result.body.hasBackgroundImage ? `${API_ORIGIN}/api/v1/profile/background_image?access_token=${accessToken}&bustcache=${Date.now()}` : '';
      result.body.avatarUrl = `${API_ORIGIN}/api/v1/profile/avatar/${result.body.id}?ts=${Date.now()}`;

      profileCached = result.body;

      return [null, result.body];
    },
    async setPassword(password, newPassword) {
      let result;
      try {
        result = await fetcher.post(`${API_ORIGIN}/api/v1/profile/password`, { password, newPassword }, { access_token: accessToken });
      } catch (e) {
        return [e];
      }

      if (result.status !== 204) return [result];
      return [null];
    },
    async setDisplayName(displayName) {
      let error, result;
      try {
        result = await fetcher.post(`${API_ORIGIN}/api/v1/profile/display_name`, { displayName }, { access_token: accessToken });
      } catch (e) {
        error = e;
      }

      if (error) return error;
      if (result.status !== 204) return result;

      return null;
    },
    async setEmail(email, password) {
      let result;
      try {
        result = await fetcher.post(`${API_ORIGIN}/api/v1/profile/email`, { email, password }, { access_token: accessToken });
      } catch (e) {
        return [e];
      }

      if (result.status !== 204) return [result];
      return [null];
    },
    async setFallbackEmail(fallbackEmail, password) {
      let result;
      try {
        result = await fetcher.post(`${API_ORIGIN}/api/v1/profile/fallback_email`, { fallbackEmail, password }, { access_token: accessToken });
      } catch (e) {
        return [e];
      }

      if (result.status !== 204) return [result];
      return [null];
    },
    async setLanguage(language) {
      let error, result;
      try {
        result = await fetcher.post(`${API_ORIGIN}/api/v1/profile/language`, { language }, { access_token: accessToken });
      } catch (e) {
        error = e;
      }

      if (error) return error;
      if (result.status !== 204) return result;

      return null;
    },
    async setAvatar(file) {
      const fd = new FormData();
      fd.append('avatar', file);

      let error, result;
      try {
        result = await fetcher.post(`${API_ORIGIN}/api/v1/profile/avatar`, fd, { access_token: accessToken });
      } catch (e) {
        error = e;
      }

      if (error) return error;
      if (result.status !== 202) return result;

      notifyChange(KEYS.AVATAR, `${API_ORIGIN}/api/v1/profile/avatar/${profileCached.id}?ts=${Date.now()}`);

      return null;
    },
    async unsetAvatar() {
      let error, result;
      try {
        result = await fetcher.del(`${API_ORIGIN}/api/v1/profile/avatar`, null, { access_token: accessToken });
      } catch (e) {
        error = e;
      }

      if (error) return error;
      if (result.status !== 204) return result;

      return null;
    },
    async setBackgroundImage(file) {
      const fd = new FormData();
      if (file) fd.append('backgroundImage', file);

      let error, result;
      try {
        result = await fetcher.post(`${API_ORIGIN}/api/v1/profile/background_image`, fd, { access_token: accessToken });
      } catch (e) {
        error = e;
      }

      if (error) return error;
      if (result.status !== 202) return result;

      return null;
    },
    async sendPasswordReset(identifier) {
      let error, result;
      try {
        result = await fetcher.post(`${API_ORIGIN}/api/v1/auth/password_reset_request`, { identifier }, { access_token: accessToken });
      } catch (e) {
        error = e;
      }

      if (error) return error;
      if (result.status !== 202) return result;

      return null;
    },
    async setTotpSecret() {
      let error, result;
      try {
        result = await fetcher.post(`${API_ORIGIN}/api/v1/profile/totp_secret`, {}, { access_token: accessToken });
      } catch (e) {
        error = e;
      }

      if (error || result.status !== 200) return [error || result];
      return [null,  result.body];
    },
    async enableTotp(totpToken) {
      let error, result;
      try {
        result = await fetcher.post(`${API_ORIGIN}/api/v1/profile/totp_enable`, { totpToken }, { access_token: accessToken });
      } catch (e) {
        error = e;
      }

      if (error || result.status !== 204) return [error || result];
      return [null];
    },
    async disableTwoFA(password) {
      let result;
      try {
        result = await fetcher.post(`${API_ORIGIN}/api/v1/profile/totp_disable`, { password }, { access_token: accessToken });
      } catch (e) {
        return [e];
      }

      if (result.status !== 204) return [result];
      return [null];
    },
    async setNotificationConfig(notificationConfig) {
      let error, result;
      try {
        result = await fetcher.post(`${API_ORIGIN}/api/v1/profile/notification_config`, { notificationConfig }, { access_token: accessToken });
      } catch (e) {
        error = e;
      }

      if (error || result.status !== 204) return [error || result];
      return [null, result.body];
    },
    async setupAccount(data) {
      let error, result;
      try {
        result = await fetcher.post(`${API_ORIGIN}/api/v1/auth/setup_account`, data);
      } catch (e) {
        error = e;
      }

      if (error || result.status !== 201) return [error || result];
      return [null, result.body];
    },
    async getPasskeyRegistrationOptions() {
      let error, result;
      try {
        result = await fetcher.post(`${API_ORIGIN}/api/v1/profile/passkey/register/options`, {}, { access_token: accessToken });
      } catch (e) {
        error = e;
      }

      if (error || result.status !== 200) return [error || result];
      return [null, result.body];
    },
    async registerPasskey(credential, name) {
      let error, result;
      try {
        result = await fetcher.post(`${API_ORIGIN}/api/v1/profile/passkey/register`, { credential, name }, { access_token: accessToken });
      } catch (e) {
        error = e;
      }

      if (error || result.status !== 201) return [error || result];
      return [null, result.body];
    },
    async deletePasskey(password) {
      let error, result;
      try {
        result = await fetcher.post(`${API_ORIGIN}/api/v1/profile/passkey/disable`, { password }, { access_token: accessToken });
      } catch (e) {
        error = e;
      }

      if (error || result.status !== 204) return [error || result];
      return [null];
    },
  };
}

export default {
  KEYS,
  onChange,
  create,
};
