import { __decorate, __metadata, __param } from "tslib";
import { addHours, subYears } from 'date-fns';
import { GraphQLError } from 'graphql';
import { Inject, Injectable, Scope } from 'graphql-modules';
import { dateToTimelessDateString } from '../../../shared/helpers/index.js';
import { ENVIRONMENT } from '../../../shared/tokens.js';
import { ProviderCredentialsProvider } from '../../provider-credentials/providers/provider-credentials.provider.js';
import { ContractSchema, downloadInvoicePdfSchema, retrieveInvoicesSchema, retrievePaymentBreakdownSchema, retrievePaymentReceiptsSchema, } from './schemas.js';
let DeelClientProvider = class DeelClientProvider {
    env;
    credentialsProvider;
    host = 'https://api.letsdeel.com/rest/v2';
    tokenPromise = null;
    constructor(env, credentialsProvider) {
        this.env = env;
        this.credentialsProvider = credentialsProvider;
    }
    // This is a workaround for the Deel API returning PST dates as UTC dates.
    timeZoneFix(dateString) {
        const date = new Date(dateString);
        return addHours(date, 7).toUTCString();
    }
    getApiToken() {
        this.tokenPromise ??= this._fetchToken();
        return this.tokenPromise;
    }
    async _fetchToken() {
        const fromDb = await this.credentialsProvider.getDeelCredentials();
        const token = fromDb?.apiToken ?? null;
        if (!token) {
            throw new GraphQLError('Deel credentials not configured for this tenant', {
                extensions: { code: 'PROVIDER_NOT_CONFIGURED' },
            });
        }
        return token;
    }
    async getPaymentReceipts() {
        try {
            const queryVars = {
                date_from: dateToTimelessDateString(subYears(new Date(), 1)),
                date_to: dateToTimelessDateString(new Date()),
            };
            const url = new URL(`${this.host}/payments`);
            Object.entries(queryVars).map(([key, value]) => {
                url.searchParams.set(key, value);
            });
            const res = await fetch(url, {
                headers: {
                    accept: 'application/json',
                    authorization: `Bearer ${await this.getApiToken()}`,
                },
            });
            if (!res.ok) {
                console.error(await res.text());
                throw new Error(`Deel API returned status ${res.status}`);
            }
            const rawData = await res.json();
            if ('errors' in rawData) {
                console.log(rawData);
                throw new Error('Deel API returned an error');
            }
            const data = retrievePaymentReceiptsSchema.parse(rawData);
            return data;
        }
        catch (error) {
            const message = 'Failed to fetch Deel payment receipts';
            console.error(`${message}: ${error}`);
            throw new Error(message, { cause: error });
        }
    }
    async getPaymentBreakdown(paymentId) {
        try {
            const url = new URL(`${this.host}/payments/${paymentId}/breakdown`);
            const res = await fetch(url, {
                headers: {
                    accept: 'application/json',
                    authorization: `Bearer ${await this.getApiToken()}`,
                },
            });
            if (!res.ok) {
                console.error(await res.text());
                throw new Error(`Deel API returned status ${res.status}`);
            }
            const rawData = await res.json();
            if ('errors' in rawData) {
                console.log(rawData);
                throw new Error('Deel API returned an error');
            }
            const data = retrievePaymentBreakdownSchema.parse(rawData);
            return data;
        }
        catch (error) {
            const message = 'Failed to fetch Deel payment breakdown';
            console.error(`${message}: ${error}`);
            throw new Error(message, { cause: error });
        }
    }
    async getSalaryInvoices() {
        const invoices = [];
        try {
            const apiToken = await this.getApiToken();
            const queryVars = {
                limit: 50,
                offset: 0,
                issued_from_date: dateToTimelessDateString(subYears(new Date(), 1)),
            };
            for (let i = 0; i < 10; i++) {
                const url = new URL(`${this.host}/invoices`);
                Object.entries({ ...queryVars, offset: i * 50 }).map(([key, value]) => {
                    url.searchParams.set(key, value);
                });
                const res = await fetch(url, {
                    headers: {
                        accept: 'application/json',
                        authorization: `Bearer ${apiToken}`,
                    },
                });
                if (!res.ok) {
                    console.error(await res.text());
                    throw new Error(`Deel API returned status ${res.status}`);
                }
                const rawData = await res.json();
                if ('errors' in rawData) {
                    console.log(rawData);
                    throw new Error('Deel API returned an error');
                }
                const data = retrieveInvoicesSchema.parse(rawData);
                if (data.data.length) {
                    data.data = data.data.map(invoice => {
                        return {
                            ...invoice,
                            issued_at: this.timeZoneFix(invoice.issued_at),
                            due_date: this.timeZoneFix(invoice.due_date),
                        };
                    });
                }
                else {
                    break;
                }
                invoices.push(...data.data);
            }
            return invoices;
        }
        catch (error) {
            const message = 'Failed to fetch Deel salary invoices';
            console.error(`${message}: ${error}`);
            throw new Error(message, { cause: error });
        }
    }
    async getSalaryInvoiceFile(id) {
        try {
            const url = new URL(`${this.host}/invoices/${id}/download`);
            const res = await fetch(url, {
                headers: {
                    accept: 'application/json',
                    authorization: `Bearer ${await this.getApiToken()}`,
                },
            });
            if (!res.ok) {
                console.error(await res.text());
                throw new Error(`Deel API returned status ${res.status}`);
            }
            const rawData = await res.json();
            const data = downloadInvoicePdfSchema.parse(rawData);
            if (!data.data.url) {
                throw new Error('Deel invoice file download URL is missing');
            }
            const invoiceFileRes = await fetch(data.data.url);
            if (!invoiceFileRes.ok) {
                throw new Error('Deel invoice file download failed');
            }
            const invoiceFileBuffer = await invoiceFileRes.arrayBuffer();
            const blob = new Blob([invoiceFileBuffer], { type: 'application/pdf' });
            return blob;
        }
        catch (error) {
            const message = 'Failed to fetch Deel invoice file';
            console.error(`${message}: ${error}`);
            throw new Error(message, { cause: error });
        }
    }
    async getContractDetails(contractId) {
        try {
            const url = new URL(`${this.host}/contracts/${contractId}`);
            const res = await fetch(url, {
                headers: {
                    accept: 'application/json',
                    authorization: `Bearer ${await this.getApiToken()}`,
                },
            });
            if (!res.ok) {
                console.error(await res.text());
                throw new Error(`Deel API returned status ${res.status}`);
            }
            const rawData = await res.json();
            if ('errors' in rawData) {
                console.log(rawData);
                throw new Error('Deel API returned an error');
            }
            const contract = ContractSchema.safeParse(rawData);
            if (!contract.success) {
                let errorMessage = 'Deel contract data validation failed';
                if (contract.error.issues) {
                    for (const issue of contract.error.issues) {
                        let value = rawData;
                        for (const pathPart of issue.path) {
                            value = value ? value[pathPart] : undefined;
                        }
                        errorMessage += `\n - Path: ${issue.path.join('.')}, Message: ${issue.message}, value: ${value}`;
                    }
                }
                throw new Error(errorMessage);
            }
            return contract.data;
        }
        catch (error) {
            const message = 'Failed to fetch Deel contract details';
            console.error(`${message}: ${error}`);
            throw new Error(message, { cause: error });
        }
    }
};
DeelClientProvider = __decorate([
    Injectable({
        scope: Scope.Operation,
        global: true,
    }),
    __param(0, Inject(ENVIRONMENT)),
    __metadata("design:paramtypes", [Object, ProviderCredentialsProvider])
], DeelClientProvider);
export { DeelClientProvider };
//# sourceMappingURL=deel-client.provider.js.map