"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
    result["default"] = mod;
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const cosmiconfig_1 = __importDefault(require("cosmiconfig"));
const grpc_1 = __importDefault(require("grpc"));
const lodash_get_1 = __importDefault(require("lodash.get"));
const auth_1 = __importDefault(require("./auth"));
const interceptor_1 = require("./interceptor");
const services = __importStar(require("./services"));
const GrpcTypes = __importStar(require("./types"));
const utils_1 = require("./utils");
// @ts-ignore
const compiled_resources_js_1 = __importDefault(require("../protos/compiled-resources.js"));
const DEFAULT_VERSION = "v1";
const GOOGLE_ADS_ENDPOINT = "googleads.googleapis.com:443";
const PROTO_ROOT = `google.ads.googleads.${DEFAULT_VERSION}`;
const allProtos = lodash_get_1.default(compiled_resources_js_1.default, PROTO_ROOT);
class GoogleAdsClient {
    constructor(options) {
        if (typeof options === "string" || typeof options === "undefined") {
            const configPath = options;
            const { config = {} } = this.loadConfig(configPath) || {};
            options = config;
        }
        this.validateOptions(options);
        if (this.usingToken(options)) {
            this.options = options;
        }
        else {
            /* Access token has not been provided */
            this.options = options;
            this.auth = new auth_1.default({
                clientId: this.options.client_id,
                clientSecret: this.options.client_secret,
                refreshToken: this.options.refresh_token,
                accessTokenGetter: this.options.accessTokenGetter,
            });
        }
    }
    getService(serviceName) {
        const serviceClientName = `${serviceName}Client`;
        if (!services.hasOwnProperty(serviceClientName)) {
            throw new Error(`Specified service "${serviceName}" does not exist in Google Ads API ${DEFAULT_VERSION}.`);
        }
        const interceptors = this.buildInterceptors();
        const serviceClientConstructor = services[serviceClientName];
        const service = new serviceClientConstructor(GOOGLE_ADS_ENDPOINT, grpc_1.default.credentials.createSsl(), {
            interceptors,
        });
        /* Promisify gRPC service methods (callbacks are kept as well) */
        utils_1.promisifyServiceClient(service);
        return service;
    }
    buildResource(resource, data) {
        if (!allProtos.resources.hasOwnProperty(resource) &&
            !allProtos.services.hasOwnProperty(resource)) {
            throw new Error(`Specified type "${resource}" does not exist in Google Ads API ${DEFAULT_VERSION}`);
        }
        /* Load the relevant types */
        const type = allProtos.resources[resource] || allProtos.services[resource];
        const grpcType = GrpcTypes[resource];
        /*
          This translates ts values, such as string, to the protobuf format
          e.g. {some_name: "campaign"} -> {someName: { value: "campaign" }}
        */
        const protoFormatData = utils_1.convertToProtoFormat(data, type);
        /* Create a new protobuf Message of the specified type */
        const message = type.fromObject(protoFormatData);
        // TODO: Include debug option that also returns the readable version of the protobuf
        /* Create a readable js object from the protobuf (useful for debugging) */
        // const readable = type.toObject(message, {
        //   enums: String, // enums as string names
        //   longs: String, // longs as strings (requires long.js)
        //   bytes: String, // bytes as base64 encoded strings
        //   defaults: true, // includes default values
        //   arrays: true, // populates empty arrays (repeated fields) even if defaults=false
        //   objects: true, // populates empty objects (map fields) even if defaults=false
        //   oneofs: true, // includes virtual oneof fields set to the present field's name
        // });
        /* Encode the protobuf so it can be translated to the specific gRPC type */
        const encoded = type.encode(message).finish();
        /* Translate the encoded protobuf type to the grpc type */
        const protobuf = grpcType.deserializeBinary(encoded);
        // return { protobuf, readable };
        return protobuf;
    }
    buildInterceptors() {
        const metadataInterceptor = new interceptor_1.MetadataInterceptor(this.options.developer_token, this.options.login_customer_id, this.options.access_token, this.auth);
        const exceptionInterceptor = new interceptor_1.ExceptionInterceptor();
        const responseParsingInterceptor = new interceptor_1.ResponseParsingInterceptor();
        const interceptors = [
            (options, nextCall) => metadataInterceptor.intercept(options, nextCall),
            (options, nextCall) => exceptionInterceptor.intercept(options, nextCall),
        ];
        if (this.options.parseResults) {
            interceptors.push((options, nextCall) => responseParsingInterceptor.intercept(options, nextCall));
        }
        return interceptors;
    }
    loadConfig(configPath) {
        const explorer = cosmiconfig_1.default("googleads");
        if (configPath) {
            return explorer.loadSync(configPath);
        }
        return explorer.searchSync();
    }
    validateOptions(options) {
        if (!options) {
            throw new Error(`Client expects initialisation options`);
        }
        if (!options.developer_token) {
            throw new Error(`Missing required key "developer_token" in options`);
        }
        if (this.usingToken(options) && !options.access_token) {
            throw new Error(`Missing required keys in options, expected "access_token", "developer_token"`);
        }
        if (!this.usingToken(options)) {
            if (!options.client_id ||
                !options.client_secret ||
                !options.refresh_token) {
                throw new Error(`Missing required keys in options, expected "client_id", "client_secret", "client_secret"`);
            }
        }
    }
    usingToken(options) {
        return "access_token" in options;
    }
}
exports.GoogleAdsClient = GoogleAdsClient;
//# sourceMappingURL=data:application/json;base64, 