var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { updateDates } from "@corejam/base";
import { FaunaClient } from "@corejam/base/dist/resolvers/db/fauna/Client";
import { query as q } from "faunadb";
import { roles, STATUS, } from "../../../../shared/types/User";
import { AuthenticationError } from "../../../Errors";
import { decodeJWT, generateTokensForUser } from "../../../Functions";
export function allUsers() {
    return FaunaClient()
        .query(q.Map(q.Paginate(q.Match(q.Index("allUsers"))), q.Lambda("x", q.Merge({ id: q.Select(["ref", "id"], q.Get(q.Var("x"))) }, q.Select("data", q.Get(q.Var("x")))))))
        .then((response) => {
        return response.data;
    });
}
export function userCreate(userCreateInput) {
    return FaunaClient()
        .query(q.Create(q.Collection("users"), {
        data: Object.assign({ email: userCreateInput.email, role: [roles.USER], active: true, status: STATUS.PENDING }, updateDates()),
        credentials: { password: userCreateInput.password },
    }))
        .then((response) => {
        return Object.assign({ id: response.ref.id }, response.data);
    });
}
export function userEdit(id, userInput) {
    return FaunaClient()
        .query(q.Update(q.Ref(q.Collection("users"), id), {
        data: Object.assign({}, userInput),
    }))
        .then((response) => {
        return Object.assign({ id: response.ref.id }, response.data);
    });
}
export function userById(id) {
    return FaunaClient()
        .query(q.Get(q.Ref(q.Collection("users"), id)))
        .then((response) => {
        return Object.assign({ id: response.ref.id }, response.data);
    });
}
export function userByToken(token) {
    const decoded = decodeJWT(token);
    return userById(decoded.id);
}
export function userByEmail(email) {
    return FaunaClient()
        .query(q.Get(q.Match(q.Index("userByEmail"), email)))
        .then((response) => {
        return Object.assign({ id: response.ref.id }, response.data);
    })
        .catch((e) => {
        if (e.message == "instance not found")
            return null;
        throw e;
    });
}
export function userRegister(userInput, _id) {
    return __awaiter(this, void 0, void 0, function* () {
        return userCreate(userInput);
    });
}
export function userAuthenticate(email, password) {
    return FaunaClient()
        .query(q.Merge(q.Login(q.Match("userByEmail", email), { password: password }), {
        user: q.Select(["data"], q.Get(q.Match("userByEmail", email))),
    }))
        .then((response) => {
        if (!response.user.active) {
            throw new AuthenticationError();
        }
        const user = Object.assign(Object.assign({}, response.user), { id: response.instance.id });
        return generateTokensForUser(user, userEdit);
    })
        .catch((_e) => {
        throw new AuthenticationError();
    });
}
export function userTokenRefresh(refreshToken) {
    return __awaiter(this, void 0, void 0, function* () {
        const decodedRefresh = decodeJWT(refreshToken);
        const user = yield userById(decodedRefresh.id);
        if (!user || !user.refreshToken) {
            throw new AuthenticationError();
        }
        return yield generateTokensForUser(user, userEdit);
    });
}
export function userUpdatePassword(user, passwordInput) {
    return __awaiter(this, void 0, void 0, function* () {
        return FaunaClient()
            .query(q.Update(q.Ref(q.Collection("users"), user.id), {
            credentials: { password: passwordInput.password },
        }))
            .then((_res) => {
            return true;
        });
    });
}
