<commit_before>const ObjectID = require('bson-objectid').default;
const {BadRequestError} = require('@tryghost/errors');
const Tier = require('./Tier');

/**
 * @typedef {object} ITierRepository
 * @prop {(id: ObjectID) => Promise<Tier>} getById
 * @prop {(tier: Tier) => Promise<void>} save
 * @prop {(options?: {filter?: string}) => Promise<Tier[]>} getAll
 */

/**
 * @typedef {object} ISlugService
 * @prop {(input: string) => Promise<string>} generate
 */

/**
 * @template {Model}
 * @typedef {object} Page<Model>
 * @prop {Model[]} data
 * @prop {object} meta
 * @prop {object} meta.pagination
 * @prop {number} meta.pagination.page - The current page
 * @prop {number} meta.pagination.pages - The total number of pages
 * @prop {number} meta.pagination.limit - The limit of models per page
 * @prop {number} meta.pagination.total - The totaL number of models across all pages
 * @prop {number|null} meta.pagination.prev - The number of the previous page, or null if there isn't one
 * @prop {number|null} meta.pagination.next - The number of the next page, or null if there isn't one
 */

module.exports = class TiersAPI {
    /** @type {ITierRepository} */
    #repository;

    /** @type {ISlugService} */
    #slugService;

    constructor(deps) {
        this.#repository = deps.repository;
        this.#slugService = deps.slugService;
    }

    /**
     * @param {object} [options]
     * @param {string} [options.filter] - An NQL filter string
     *
     * @returns {Promise<Page<Tier>>}
     */
    async browse(options = {}) {
        const tiers = await this.#repository.getAll(options);

        return {
            data: tiers,
            meta: {
                pagination: {
                    page: 1,
                    pages: 1,
                    limit: tiers.length,
                    total: tiers.length,
                    prev: null,
                    next: null
                }
            }
        };
    }

    /**
     * @param {string} idString
     *
     * @returns {Promise<Tier>}
     */
    async read(idString) {
        const id = ObjectID.createFromHexString(idString);
        const tier = await this.#repository.getById(id);

        return tier;
    }

    /**
     * @param {string} id
     * @param {object} data
     * @returns {Promise<Tier>}
     */
    async edit(idString, data) {
        const id = ObjectID.createFromHexString(idString);
        const tier = await this.#repository.getById(id);

        const editableProperties = [
            'name',
            'benefits',
            'description',
            'visibility',
            'active',
            'trialDays',
            'currency',
            'monthlyPrice',
            'yearlyPrice',
            'welcomePageURL'
        ];

        for (const editableProperty of editableProperties) {
            if (Reflect.has(data, editableProperty)) {
                tier[editableProperty] = data[editableProperty];
            }
        }

        await this.#repository.save(tier);

        return tier;
    }

    /**
     * @param {object} data
     * @returns {Promise<Tier>}
     */
    async add(data) {
        if (data.type !== 'paid') {
            throw new BadRequestError({
                message: 'Cannot create free Tier'
            });
        }<commit_msg>Fixed add method for TiersAPI<commit_after>const ObjectID = require('bson-objectid').default;
const {BadRequestError} = require('@tryghost/errors');
const Tier = require('./Tier');

/**
 * @typedef {object} ITierRepository
 * @prop {(id: ObjectID) => Promise<Tier>} getById
 * @prop {(tier: Tier) => Promise<void>} save
 * @prop {(options?: {filter?: string}) => Promise<Tier[]>} getAll
 */

/**
 * @typedef {object} ISlugService
 * @prop {(input: string) => Promise<string>} generate
 */

/**
 * @template {Model}
 * @typedef {object} Page<Model>
 * @prop {Model[]} data
 * @prop {object} meta
 * @prop {object} meta.pagination
 * @prop {number} meta.pagination.page - The current page
 * @prop {number} meta.pagination.pages - The total number of pages
 * @prop {number} meta.pagination.limit - The limit of models per page
 * @prop {number} meta.pagination.total - The totaL number of models across all pages
 * @prop {number|null} meta.pagination.prev - The number of the previous page, or null if there isn't one
 * @prop {number|null} meta.pagination.next - The number of the next page, or null if there isn't one
 */

module.exports = class TiersAPI {
    /** @type {ITierRepository} */
    #repository;

    /** @type {ISlugService} */
    #slugService;

    constructor(deps) {
        this.#repository = deps.repository;
        this.#slugService = deps.slugService;
    }

    /**
     * @param {object} [options]
     * @param {string} [options.filter] - An NQL filter string
     *
     * @returns {Promise<Page<Tier>>}
     */
    async browse(options = {}) {
        const tiers = await this.#repository.getAll(options);

        return {
            data: tiers,
            meta: {
                pagination: {
                    page: 1,
                    pages: 1,
                    limit: tiers.length,
                    total: tiers.length,
                    prev: null,
                    next: null
                }
            }
        };
    }

    /**
     * @param {string} idString
     *
     * @returns {Promise<Tier>}
     */
    async read(idString) {
        const id = ObjectID.createFromHexString(idString);
        const tier = await this.#repository.getById(id);

        return tier;
    }

    /**
     * @param {string} id
     * @param {object} data
     * @returns {Promise<Tier>}
     */
    async edit(idString, data) {
        const id = ObjectID.createFromHexString(idString);
        const tier = await this.#repository.getById(id);

        const editableProperties = [
            'name',
            'benefits',
            'description',
            'visibility',
            'active',
            'trialDays',
            'currency',
            'monthlyPrice',
            'yearlyPrice',
            'welcomePageURL'
        ];

        for (const editableProperty of editableProperties) {
            if (Reflect.has(data, editableProperty)) {
                tier[editableProperty] = data[editableProperty];
            }
        }

        await this.#repository.save(tier);

        return tier;
    }

    /**
     * @param {object} data
     * @returns {Promise<Tier>}
     */
    async add(data) {
        if (data.type === 'free') {
            throw new BadRequestError({
                message: 'Cannot create free Tier'
            });
        }
{'fraction_non_alphanumeric': 0.13333333333333333, 'fraction_numerical': 0.0006033182503770739, 'mean_word_length': 1.9589468987059349, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4198261', 'n_tokens_mistral': 1999, 'n_tokens_neox': 1919, 'n_words': 488}