import { FormType } from "../../Components/Forms/ModelForm";
import { APP_API_URL } from "../../Config";
import Navigation from "../Navigation";
import ProjectUtil from "../Project";
import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
import HTTPMethod from "../../../Types/API/HTTPMethod";
import HTTPResponse from "../../../Types/API/HTTPResponse";
import Route from "../../../Types/API/Route";
import URL from "../../../Types/API/URL";
import BadDataException from "../../../Types/Exception/BadDataException";
import JSONFunctions from "../../../Types/JSONFunctions";
import API from "../API/API";
export class ModelAPIHttpResponse extends HTTPResponse {
}
export default class ModelAPI {
    static async create(data) {
        return await ModelAPI.createOrUpdate({
            model: data.model,
            modelType: data.modelType,
            formType: FormType.Create,
            miscDataProps: {},
            requestOptions: data.requestOptions,
        });
    }
    static async update(data) {
        return await ModelAPI.createOrUpdate({
            model: data.model,
            modelType: data.modelType,
            formType: FormType.Update,
        });
    }
    static async updateById(data) {
        var _a;
        const model = new data.modelType();
        let apiUrl = data.apiUrlOverride || null;
        if (!apiUrl) {
            const apiPath = model.getCrudApiPath();
            if (!apiPath) {
                throw new BadDataException("This model does not support create or update operations.");
            }
            apiUrl = URL.fromURL(APP_API_URL).addRoute(apiPath);
        }
        apiUrl = apiUrl.addRoute(`/${data.id.toString()}`);
        const result = await API.fetch(Object.assign({ method: HTTPMethod.PUT, url: apiUrl, data: {
                data: data.data,
            }, headers: this.getCommonHeaders(data.requestOptions) }, (((_a = data.requestOptions) === null || _a === void 0 ? void 0 : _a.apiRequestOptions)
            ? { options: data.requestOptions.apiRequestOptions }
            : {})));
        if (result.isSuccess()) {
            return result;
        }
        this.checkStatusCode(result);
        throw result;
    }
    static async createOrUpdate(data) {
        var _a, _b, _c, _d;
        let apiUrl = ((_a = data.requestOptions) === null || _a === void 0 ? void 0 : _a.overrideRequestUrl) || null;
        if (!apiUrl) {
            const apiPath = data.model.getCrudApiPath();
            if (!apiPath) {
                throw new BadDataException("This model does not support create or update operations.");
            }
            apiUrl = URL.fromURL(APP_API_URL).addRoute(apiPath);
        }
        const httpMethod = data.formType === FormType.Create ? HTTPMethod.POST : HTTPMethod.PUT;
        if (httpMethod === HTTPMethod.PUT &&
            !((_b = data.requestOptions) === null || _b === void 0 ? void 0 : _b.overrideRequestUrl)) {
            apiUrl = apiUrl.addRoute(`/${data.model._id}`);
        }
        const apiResult = await API.fetch(Object.assign({ method: httpMethod, url: apiUrl, data: {
                data: JSONFunctions.serialize(BaseModel.toJSON(data.model, data.modelType)),
                miscDataProps: data.miscDataProps || {},
            }, headers: Object.assign(Object.assign({}, this.getCommonHeaders(data.requestOptions)), (((_c = data.requestOptions) === null || _c === void 0 ? void 0 : _c.requestHeaders) || {})) }, (((_d = data.requestOptions) === null || _d === void 0 ? void 0 : _d.apiRequestOptions)
            ? { options: data.requestOptions.apiRequestOptions }
            : {})));
        if (apiResult.isSuccess() && apiResult instanceof HTTPResponse) {
            const result = apiResult;
            if (result.data["_miscData"]) {
                result.miscData = result.data["_miscData"];
                delete result.data["_miscData"];
            }
            result.data = BaseModel.fromJSONObject(result.data, data.modelType);
            return result;
        }
        this.checkStatusCode(apiResult);
        throw apiResult;
    }
    static async getList(data) {
        var _a, _b;
        const model = new data.modelType();
        const apiPath = model.getCrudApiPath();
        if (!apiPath) {
            throw new BadDataException("This model does not support list operations.");
        }
        let apiUrl = URL.fromURL(APP_API_URL)
            .addRoute(apiPath)
            .addRoute("/get-list");
        if ((_a = data.requestOptions) === null || _a === void 0 ? void 0 : _a.overrideRequestUrl) {
            apiUrl = data.requestOptions.overrideRequestUrl;
        }
        if (!apiUrl) {
            throw new BadDataException("This model does not support list operations.");
        }
        const headers = this.getCommonHeaders(data.requestOptions);
        if (data.requestOptions && data.requestOptions.isMultiTenantRequest) {
            headers["isMultiTenantRequest"] = "true";
        }
        const result = await API.fetch(Object.assign({ method: HTTPMethod.POST, url: apiUrl, data: {
                query: JSONFunctions.serialize(data.query),
                select: JSONFunctions.serialize(data.select),
                sort: JSONFunctions.serialize(data.sort),
                groupBy: JSONFunctions.serialize(data.groupBy),
            }, headers, params: {
                limit: data.limit.toString(),
                skip: data.skip.toString(),
            } }, (((_b = data.requestOptions) === null || _b === void 0 ? void 0 : _b.apiRequestOptions)
            ? { options: data.requestOptions.apiRequestOptions }
            : {})));
        if (result.isSuccess()) {
            const list = BaseModel.fromJSONArray(result.data, data.modelType);
            return {
                data: list,
                count: result.count,
                skip: result.skip,
                limit: result.limit,
            };
        }
        this.checkStatusCode(result);
        throw result;
    }
    static async count(data) {
        var _a, _b;
        const model = new data.modelType();
        const apiPath = model.getCrudApiPath();
        if (!apiPath) {
            throw new BadDataException("This model does not support list operations.");
        }
        let apiUrl = URL.fromURL(APP_API_URL)
            .addRoute(apiPath)
            .addRoute("/count");
        if ((_a = data.requestOptions) === null || _a === void 0 ? void 0 : _a.overrideRequestUrl) {
            apiUrl = data.requestOptions.overrideRequestUrl;
        }
        if (!apiUrl) {
            throw new BadDataException("This model does not support count operations.");
        }
        const headers = this.getCommonHeaders(data.requestOptions);
        if (data.requestOptions && data.requestOptions.isMultiTenantRequest) {
            headers["is-multi-tenant-query"] = "true";
        }
        const result = await API.fetch(Object.assign({ method: HTTPMethod.POST, url: apiUrl, data: {
                query: JSONFunctions.serialize(data.query),
            }, headers }, (((_b = data.requestOptions) === null || _b === void 0 ? void 0 : _b.apiRequestOptions)
            ? { options: data.requestOptions.apiRequestOptions }
            : {})));
        if (result.isSuccess()) {
            const count = result.data["count"];
            return count;
        }
        this.checkStatusCode(result);
        throw result;
    }
    static getCommonHeaders(requestOptions) {
        let headers = {};
        if (!requestOptions ||
            !requestOptions.isMultiTenantRequest ||
            Object.keys(requestOptions).length === 0) {
            const project = ProjectUtil.getCurrentProject();
            if (project && project.id) {
                headers["tenantid"] = project.id.toString();
            }
            else {
                /*
                 * Fallback to getCurrentProjectId() when full project data is not yet loaded
                 * This can happen after SSO login when the project ID is available in URL/SessionStorage
                 * but the full project data hasn't been fetched yet
                 */
                const projectId = ProjectUtil.getCurrentProjectId();
                if (projectId) {
                    headers["tenantid"] = projectId.toString();
                }
            }
        }
        // add SSO headers.
        headers = Object.assign({}, headers);
        if (requestOptions && requestOptions.isMultiTenantRequest) {
            headers["is-multi-tenant-query"] = "true";
        }
        return headers;
    }
    static async getItem(data) {
        var _a;
        const apiPath = new data.modelType().getCrudApiPath();
        if (!apiPath) {
            throw new BadDataException("This model does not support get operations.");
        }
        let apiUrl = URL.fromURL(APP_API_URL)
            .addRoute(apiPath)
            .addRoute("/" + data.id.toString())
            .addRoute("/get-item");
        if ((_a = data.requestOptions) === null || _a === void 0 ? void 0 : _a.overrideRequestUrl) {
            apiUrl = data.requestOptions.overrideRequestUrl;
        }
        if (!apiUrl) {
            throw new BadDataException("This model does not support get operations.");
        }
        return this.post({
            modelType: data.modelType,
            apiUrl: apiUrl,
            select: data.select,
            requestOptions: data.requestOptions,
        });
    }
    static async post(data) {
        var _a;
        const result = await API.fetch(Object.assign({ method: HTTPMethod.POST, url: data.apiUrl, data: {
                select: JSONFunctions.serialize(data.select) || {},
            }, headers: this.getCommonHeaders(data.requestOptions) }, (((_a = data.requestOptions) === null || _a === void 0 ? void 0 : _a.apiRequestOptions)
            ? { options: data.requestOptions.apiRequestOptions }
            : {})));
        if (result.isSuccess()) {
            const baseModel = BaseModel.fromJSONObject(result.data, data.modelType);
            return baseModel;
        }
        this.checkStatusCode(result);
        throw result;
    }
    static async deleteItem(data) {
        var _a;
        const apiPath = new data.modelType().getCrudApiPath();
        if (!apiPath) {
            throw new BadDataException("This model does not support delete operations.");
        }
        const apiUrl = URL.fromURL(APP_API_URL)
            .addRoute(apiPath)
            .addRoute("/" + data.id.toString());
        if (!apiUrl) {
            throw new BadDataException("This model does not support delete operations.");
        }
        const result = await API.fetch(Object.assign({ method: HTTPMethod.DELETE, url: apiUrl, headers: this.getCommonHeaders(data.requestOptions) }, (((_a = data.requestOptions) === null || _a === void 0 ? void 0 : _a.apiRequestOptions)
            ? { options: data.requestOptions.apiRequestOptions }
            : {})));
        if (result.isSuccess()) {
            return;
        }
        this.checkStatusCode(result);
        throw result;
    }
    static checkStatusCode(result) {
        if (result.statusCode === 406) {
            const project = ProjectUtil.getCurrentProject();
            if (project && project.id) {
                Navigation.navigate(new Route(`/dashboard/${project._id}/sso`));
            }
        }
    }
}
//# sourceMappingURL=ModelAPI.js.map