/**
 * @module createYahooFinance
 */
import * as dntShim from "../_dnt.shims.js";
import { setOptions, validateOptions, } from "./lib/options/options.js";
import yahooFinanceFetch from "./lib/yahooFinanceFetch.js";
import moduleExec from "./lib/moduleExec.js";
import Notices from "./lib/notices.js";
import { assertSupported } from "./lib/runtime-detect.js";
import defaultOptions from "./lib/options/defaults.js";
import { deepMerge } from "./lib/deepmerge.js";
const MIN_SUPPORTED_RUNTIMES = {
    node: "22.0.0",
    deno: "2.0.0",
    bun: "1.0.0",
    cloudflare: {
        requireFeatures: [],
    },
};
/**
 * Instantiate a new YahooFinance client.
 *
 * See {@linkcode YahooFinanceOptions} for available options.
 *
 * @example
 * ```ts
 * const yahooFinance = new YahooFinance(); // or YahooFinance({ ...options });
 * console.log(await yahooFinance.quote("AAPL"));
 * ```
 *
 * Internal / private properties (prefixed `_`) and shown below are not part of the public API and should not be depended on.
 * You're welcome to inspect or make use of them but they might change or disappear without notice.
 *
 * @see The full list of {@link [modules] main modules} and {@link [other] other modules}.
 * @see {@linkcode [createYahooFinance].createYahooFinance createYahooFinance} for creating an API client with custom modules (advanced use-cases only).
 * @see The {@link ../../~/default.html | default} entry point that includes all modules.
 */
export class YahooFinance {
    _setOpts(options) {
        setOptions.call(this, options);
    }
    constructor(options) {
        Object.defineProperty(this, "_opts", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "_fetch", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "_moduleExec", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "_notices", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        // XXX TODO remove
        Object.defineProperty(this, "_env", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "_logObj", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        this._fetch = yahooFinanceFetch;
        this._moduleExec = moduleExec;
        // XXX TODO remove
        this._env = {
            fetch: null,
        };
        if ("_createOpts" in this) {
            const createOpts = this._createOpts;
            this._opts = deepMerge(defaultOptions, createOpts["_opts"] ?? {}, options ?? {});
            if ("_allowAdditionalProps" in createOpts) {
                if (!this._opts.validation)
                    this._opts.validation = {};
                this._opts.validation.allowAdditionalProps = false;
            }
            if ("fetchDevel" in createOpts) {
                // @ts-expect-error: later
                this._env.fetchDevel = createOpts.fetchDevel;
            }
        }
        else {
            this._opts = deepMerge(defaultOptions, options ?? {});
        }
        // The following rely on this._opts being set
        this._notices = new Notices(this);
        // deno-coverage-ignore-start
        // @ts-ignore: relevant for ts-json-schema-generator
        this._logObj = dntShim.Deno.stdout.isTerminal()
            // deno-lint-ignore no-explicit-any
            ? (obj, opts) => this._opts.logger.dir(obj, { depth: opts?.depth ?? 4, colors: true })
            // deno-lint-ignore no-explicit-any
            : (obj) => this._opts.logger.info(JSON.stringify(obj, null, 2));
        // deno-coverage-ignore-stop
        // Validate options after setting up logger, etc.
        validateOptions.call(this, options ?? {}, "#constructor");
        try {
            assertSupported(MIN_SUPPORTED_RUNTIMES);
        }
        catch (error) {
            const warning = ". Things might break or work unexpectedly!";
            if (error instanceof Error) {
                this._opts.logger.warn("[yahoo-finance2] " + error.message + warning);
            }
            else {
                this._opts.logger.warn("[yahoo-finance2] " + JSON.stringify(error) + warning);
            }
        }
    }
}
/**
 * Create a new YahooFinance **class** with the given options (usually a list of modules,
 * or special options useful for testing).
 *
 * @example Basic Example
 * ```ts
 * import quote from "yahoo-finance2/modules/quote.ts";
 * import search from "yahoo-finance2/modules/search.ts";
 *
 * // Create a YahooFinance instance with the quote and search modules only.
 * const yahooFinance = createYahooFinance({
 *   modules: { quote, search }
 * });
 * ```
 *
 * By using only the modules you need, you'll have a small bundle size.  But remember,
 * `yahoo-finance2` is never bundled to the client (browser), so your savings will be
 * will be marginal (e.g. a marginally faster serverless cold start time).
 *
 * @param createOpts The {@link CreateYahooFinanceOptions} that influence the class creation.
 * @returns A {@link YahooFinance} class that you can call with `new YahooFinance()`.
 */
export default function createYahooFinance(createOpts) {
    const { modules, ...rest } = createOpts;
    Object.assign(YahooFinance.prototype, modules);
    Object.assign(YahooFinance.prototype, { _createOpts: rest });
    Object.assign(YahooFinance, Object.fromEntries(Object.keys(modules).map((key) => [key, function () {
            throw new Error("Call `const yahooFinance = new YahooFinance()` first.  Upgrading from v2?  See " +
                "https://github.com/gadicc/yahoo-finance2/blob/dev/docs/UPGRADING.md.");
        }])));
    return YahooFinance;
}
