import arrayIncludes from "./_arrayIncludes";
import arrayIncludesWith from "./_arrayIncludesWith";
import map from "../#map";

/**
 * The base implementation of methods like `difference` without support
 * for excluding multiple arrays.
 *
 * @private
 * @param {Array} array The array to inspect.
 * @param {Array} values The values to exclude.
 * @param {Function} [iteratee] The iteratee invoked per element.
 * @param {Function} [comparator] The comparator invoked per element.
 * @returns {Array} Returns the new array of filtered values.
 */

function baseDifference<T, S extends T>(array: Array<any>, values: Array<any>, iteratee?: (value: T) => S, comparator?: (value: S) => any): Array<T> {
    let index = -1;
    let includes: any = arrayIncludes;
    let isCommon = true;
    const result: Array<T> = [];
    const length = array.length;
    const valuesLength = values.length;

    if (!array.length) {
        return result;
    }
    if (iteratee) {
        values = map(values, value => iteratee(value));
    }
    if (comparator) {
        includes = arrayIncludesWith;
        isCommon = false;
    }
    outer: while (++index < length) {
        let value = array[index];
        const computed = iteratee == null ? value : iteratee(value);

        value = (comparator || value !== 0 ? value : 0) as T;
        if (isCommon && computed === computed) {
            let valuesIndex = valuesLength;
            while (valuesIndex--) {
                if (values[valuesIndex] === computed) {
                    continue outer;
                }
            }
            result.push(value);
        } else if (!includes(values, computed, comparator)) {
            result.push(value);
        }
    }
    return result;
}

export default baseDifference;
// import SetCache from "./SetCache.js";
// import arrayIncludes from "./arrayIncludes.js";
// import arrayIncludesWith from "./arrayIncludesWith.js";
// import map from "../map.js";
// import cacheHas from "./cacheHas.js";

// /** Used as the size to enable large array optimizations. */
// const LARGE_ARRAY_SIZE = 200;

// /**
//  * The base implementation of methods like `difference` without support
//  * for excluding multiple arrays.
//  *
//  * @private
//  * @param {Array} array The array to inspect.
//  * @param {Array} values The values to exclude.
//  * @param {Function} [iteratee] The iteratee invoked per element.
//  * @param {Function} [comparator] The comparator invoked per element.
//  * @returns {Array} Returns the new array of filtered values.
//  */
// function baseDifference(array, values, iteratee, comparator) {
//     let includes = arrayIncludes;
//     let isCommon = true;
//     const result = [];
//     const valuesLength = values.length;

//     if (!array.length) {
//         return result;
//     }
//     if (iteratee) {
//         values = map(values, value => iteratee(value));
//     }
//     if (comparator) {
//         includes = arrayIncludesWith;
//         isCommon = false;
//     } else if (values.length >= LARGE_ARRAY_SIZE) {
//         includes = cacheHas;
//         isCommon = false;
//         values = new SetCache(values);
//     }
//     outer: for (let value of array) {
//         const computed = iteratee == null ? value : iteratee(value);

//         value = comparator || value !== 0 ? value : 0;
//         if (isCommon && computed === computed) {
//             let valuesIndex = valuesLength;
//             while (valuesIndex--) {
//                 if (values[valuesIndex] === computed) {
//                     continue outer;
//                 }
//             }
//             result.push(value);
//         } else if (!includes(values, computed, comparator)) {
//             result.push(value);
//         }
//     }
//     return result;
// }

// export default baseDifference;
