import { __decorate, __metadata, __param } from "tslib";
import { GraphQLError } from 'graphql';
import { Inject, Injectable, Scope } from 'graphql-modules';
import { sql } from '@pgtyped/runtime';
import { ENVIRONMENT } from '../../../shared/tokens.js';
import { TenantAwareDBClient } from '../../app-providers/tenant-db-client.js';
import { decryptCredential, encryptCredential } from '../helpers/encryption.js';
import { DeelPayloadSchema, GreenInvoicePayloadSchema, } from '../helpers/payload-schemas.js';
const PROVIDER_SCHEMAS = {
    green_invoice: GreenInvoicePayloadSchema,
    deel: DeelPayloadSchema,
};
const upsertProviderCredentials = sql `
  INSERT INTO accounter_schema.provider_credentials (owner_id, provider, payload)
  VALUES (accounter_schema.get_current_business_id(), $provider, $encrypted)
  ON CONFLICT (owner_id, provider) DO UPDATE SET payload = EXCLUDED.payload, updated_at = now()
  RETURNING updated_at;`;
const deleteProviderCredentials = sql `
  DELETE FROM accounter_schema.provider_credentials
  WHERE owner_id = accounter_schema.get_current_business_id()
    AND provider = $provider;`;
const getProviderStatuses = sql `
  SELECT provider, updated_at
  FROM accounter_schema.provider_credentials
  WHERE owner_id = accounter_schema.get_current_business_id();`;
const getProviderCredentialPayload = sql `
  SELECT payload
  FROM accounter_schema.provider_credentials
  WHERE owner_id = accounter_schema.get_current_business_id()
    AND provider = $provider;`;
let ProviderCredentialsProvider = class ProviderCredentialsProvider {
    db;
    env;
    constructor(db, env) {
        this.db = db;
        this.env = env;
    }
    get encryptionKey() {
        const key = this.env.credentialsEncryptionKey;
        if (!key) {
            throw new GraphQLError('Credentials encryption key is not configured', {
                extensions: { code: 'INTERNAL_SERVER_ERROR' },
            });
        }
        return key;
    }
    async setCredentials(provider, payload) {
        const schema = PROVIDER_SCHEMAS[provider];
        const result = schema.safeParse(payload);
        if (!result.success) {
            throw new GraphQLError(`Invalid credentials for provider "${provider}"`, {
                extensions: { code: 'BAD_USER_INPUT', details: result.error.flatten() },
            });
        }
        const encrypted = encryptCredential(JSON.stringify(result.data), this.encryptionKey);
        const credentials = await upsertProviderCredentials.run({ provider, encrypted }, this.db);
        return credentials[0]?.updated_at;
    }
    async deleteCredentials(provider) {
        await deleteProviderCredentials.run({ provider }, this.db);
    }
    async getProviderStatuses() {
        const rows = await getProviderStatuses.run(undefined, this.db);
        return rows.map(row => ({
            provider: row.provider,
            configuredAt: row.updated_at.toISOString(),
        }));
    }
    async getGreenInvoiceCredentials() {
        return this._getDecrypted('green_invoice', GreenInvoicePayloadSchema);
    }
    async getDeelCredentials() {
        return this._getDecrypted('deel', DeelPayloadSchema);
    }
    async _getDecrypted(provider, schema) {
        const rows = await getProviderCredentialPayload.run({ provider }, this.db);
        if (rows.length === 0)
            return null;
        try {
            const plaintext = decryptCredential(rows[0].payload, this.encryptionKey);
            return schema.parse(JSON.parse(plaintext));
        }
        catch (err) {
            console.error(`[ProviderCredentialsProvider] Failed to decrypt/parse "${provider}" credentials: ${err instanceof Error ? err.message : String(err)}`);
            throw new GraphQLError('Failed to retrieve provider credentials', {
                extensions: { code: 'INTERNAL_SERVER_ERROR' },
            });
        }
    }
};
ProviderCredentialsProvider = __decorate([
    Injectable({ scope: Scope.Operation, global: true }),
    __param(1, Inject(ENVIRONMENT)),
    __metadata("design:paramtypes", [TenantAwareDBClient, Object])
], ProviderCredentialsProvider);
export { ProviderCredentialsProvider };
//# sourceMappingURL=provider-credentials.provider.js.map