import * as SecureStore from 'expo-secure-store';
import { action, makeObservable, observable } from "mobx";

/**
 * Represents OIDC ID token.
 */
export interface IdToken {
    sub: string
}

/**
 * A mobx store responsible for holding the current access token, refresh token and userId in memory and in Expo's [SecureStore]{@link https://docs.expo.dev/versions/latest/sdk/securestore/}.
 * Used by {@link Atlas}
 * @category Stores
 */
class AuthStore {
    /**
     * A string representing the OAuth2 access token issued to the user when they authenticate. It is sent in the Authorization header of all subsequent XHR requests in order to use authorized API endpoints.
     * For more information on OAuth2 and OpenIdConnect, visit {@link https://openid.net/connect/} and {@link https://oauth.net/2/}.
     * @memberOf AuthStore
     */
    accessToken?: string | null = null;
    /**
     * A string representing the OAuth2 refresh token issued to the user when they authenticate. It is sent to the identity provider to retrieve a new access token when the previous access token expires.
     * @memberOf AuthStore
     */
    refreshToken?: string | null = null;
    /**
     * A string representing the OAuth2 refresh token issued to the user when they authenticate. It is used to retrieve the users information from the API and to link objects created by the user to the user.
     */
    userId?: string = undefined;
    /**
     * A string representing the expo notification token.
     */
    notificationToken?: string = undefined;

    /**
     * Constructor. Uses mobx's [makeObservable]{@linkcode https://mobx.js.org/observable-state.html} to register actions and observable elements.
     */
    constructor() {
        makeObservable(this, {
            accessToken: observable,
            refreshToken: observable,
            userId: observable,
            notificationToken: observable,
            setAccessTokenAsync: action,
            setRefreshTokenAsync: action,
            setIdAsync: action,
            setNotificationToken: action
        });
    }

    /**
     * Uses the given access token value to set {@linkcode accessToken} and the 'access' element in the secure store.
     */
    async setAccessTokenAsync(tokenValue: string | null) {
        this.accessToken = tokenValue;
        if (this.accessToken) {
            await SecureStore.setItemAsync('access', this.accessToken);    
        }
        else 
        {
            await SecureStore.deleteItemAsync('access');    
        }
    }

    /**
     * Uses the given refresh token value to set {@linkcode refreshToken} and the 'refresh' element in the secure store.
     */
    async setRefreshTokenAsync(tokenValue: string | null) {
        this.refreshToken = tokenValue;
        if (this.accessToken) {
            await SecureStore.setItemAsync('refresh', this.accessToken);    
        }
        else 
        {
            await SecureStore.deleteItemAsync('refresh');    
        }
    }

    /**
     * Uses the given user id value to set {@linkcode userId} and the 'id' element in the secure store.
     */
    async setIdAsync(id?: string) {
        this.userId = id;
        if (this.userId) {
            await SecureStore.setItemAsync('id', this.userId);    
        }
        else 
        {
            await SecureStore.deleteItemAsync('id');    
        }
    }

    /**
     * Uses the given notification token value to set {@linkcode notificationToken} and the 'notif-token' element in the secure store.
     */
     async setNotificationToken(token?: string) {
        this.notificationToken = token;
        if (this.notificationToken) {
            await SecureStore.setItemAsync('notif-token', this.notificationToken);    
        }
        else 
        {
            await SecureStore.deleteItemAsync('notif-token');    
        }
    }
}

export const authStore = new AuthStore();