import { Eq, Ord } from '../typeclasses/index.js';
import '@typesugar/core';
import '../typeclasses/flatmap.js';
import '@typesugar/macros';
import 'typescript';
import '../comprehension-utils-CrcEKA_W.js';

/**
 * Tuple Utilities
 *
 * Inspired by:
 * - Scala (Tuple2..Tuple22, swap, map, productIterator)
 * - Haskell (fst, snd, swap, curry, uncurry, both, bimap)
 * - Kotlin (Pair, Triple, toList, first, second, third)
 * - Rust ((A, B) with .0, .1, swap)
 * - Python (namedtuple, tuple unpacking)
 */
type Pair<A, B> = readonly [A, B];
declare function pair<A, B>(a: A, b: B): Pair<A, B>;
declare function fst<A, B>(p: Pair<A, B>): A;
declare function snd<A, B>(p: Pair<A, B>): B;
declare function swap<A, B>(p: Pair<A, B>): Pair<B, A>;
declare function mapFst<A, B, C>(p: Pair<A, B>, fn: (a: A) => C): Pair<C, B>;
declare function mapSnd<A, B, C>(p: Pair<A, B>, fn: (b: B) => C): Pair<A, C>;
declare function bimap<A, B, C, D>(p: Pair<A, B>, f: (a: A) => C, g: (b: B) => D): Pair<C, D>;
/** Apply the same function to both elements. Haskell's `both`. */
declare function both<A, B>(p: Pair<A, A>, fn: (a: A) => B): Pair<B, B>;
declare function pairToArray<A>(p: Pair<A, A>): A[];
/** Haskell's `curry`: converts a function on pairs to a curried function. */
declare function curryPair<A, B, C>(fn: (p: Pair<A, B>) => C): (a: A) => (b: B) => C;
/** Haskell's `uncurry`: converts a curried function to one on pairs. */
declare function uncurryPair<A, B, C>(fn: (a: A, b: B) => C): (p: Pair<A, B>) => C;
type Triple<A, B, C> = readonly [A, B, C];
declare function triple<A, B, C>(a: A, b: B, c: C): Triple<A, B, C>;
declare function tripleFirst<A, B, C>(t: Triple<A, B, C>): A;
declare function tripleSecond<A, B, C>(t: Triple<A, B, C>): B;
declare function tripleThird<A, B, C>(t: Triple<A, B, C>): C;
declare function tripleToArray<A>(t: Triple<A, A, A>): A[];
declare function tripleMap<A, B, C, D, E, F>(t: Triple<A, B, C>, f: (a: A) => D, g: (b: B) => E, h: (c: C) => F): Triple<D, E, F>;

/**
 * Eq instance for Pair.
 * Compares both elements using the provided Eq instances.
 */
declare function eqPair<A, B>(eqA: Eq<A>, eqB: Eq<B>): Eq<Pair<A, B>>;
/**
 * Ord instance for Pair.
 * Compares lexicographically: first by first element, then by second.
 */
declare function ordPair<A, B>(ordA: Ord<A>, ordB: Ord<B>): Ord<Pair<A, B>>;
/**
 * Eq instance for Triple.
 * Compares all three elements using the provided Eq instances.
 */
declare function eqTriple<A, B, C>(eqA: Eq<A>, eqB: Eq<B>, eqC: Eq<C>): Eq<Triple<A, B, C>>;
/**
 * Ord instance for Triple.
 * Compares lexicographically: first, then second, then third.
 */
declare function ordTriple<A, B, C>(ordA: Ord<A>, ordB: Ord<B>, ordC: Ord<C>): Ord<Triple<A, B, C>>;
/** Zip two arrays into an array of pairs. */
declare function zipToPairs<A, B>(as: readonly A[], bs: readonly B[]): Pair<A, B>[];
/** Unzip an array of pairs into a pair of arrays. */
declare function unzipPairs<A, B>(pairs: readonly Pair<A, B>[]): Pair<A[], B[]>;
declare const TupleExt: {
    readonly pair: typeof pair;
    readonly fst: typeof fst;
    readonly snd: typeof snd;
    readonly swap: typeof swap;
    readonly mapFst: typeof mapFst;
    readonly mapSnd: typeof mapSnd;
    readonly bimap: typeof bimap;
    readonly both: typeof both;
    readonly toArray: typeof pairToArray;
    readonly curry: typeof curryPair;
    readonly uncurry: typeof uncurryPair;
    readonly triple: typeof triple;
    readonly tripleFirst: typeof tripleFirst;
    readonly tripleSecond: typeof tripleSecond;
    readonly tripleThird: typeof tripleThird;
    readonly tripleToArray: typeof tripleToArray;
    readonly tripleMap: typeof tripleMap;
    readonly zipToPairs: typeof zipToPairs;
    readonly unzipPairs: typeof unzipPairs;
};

/**
 * Range Type
 *
 * Inspired by:
 * - Scala (Range, NumericRange, inclusive/exclusive, by, contains, map, foreach)
 * - Kotlin (IntRange, LongRange, CharRange, step, reversed, contains, first, last)
 * - Rust (Range, RangeInclusive, Iterator trait on ranges)
 * - Haskell ([1..10], [1,3..10], enumFromTo, enumFromThenTo)
 * - Python (range, slice)
 * - Ruby (Range, each, step, include?, to_a)
 */
interface Range {
    readonly start: number;
    readonly end: number;
    readonly step: number;
    readonly inclusive: boolean;
}
declare function range(start: number, end: number, step?: number): Range;
declare function rangeInclusive(start: number, end: number, step?: number): Range;
declare function rangeBy(r: Range, step: number): Range;
declare function rangeReversed(r: Range): Range;
declare function rangeIterator(r: Range): IterableIterator<number>;
declare function rangeToArray(r: Range): number[];
declare function rangeForEach(r: Range, fn: (n: number, index: number) => void): void;
declare function rangeMap<A>(r: Range, fn: (n: number, index: number) => A): A[];
declare function rangeFilter(r: Range, pred: (n: number) => boolean): number[];
declare function rangeReduce<A>(r: Range, init: A, fn: (acc: A, n: number) => A): A;
declare function rangeContains(r: Range, value: number): boolean;
declare function rangeSize(r: Range): number;
declare function rangeFirst(r: Range): number | undefined;
declare function rangeLast(r: Range): number | undefined;
declare function rangeIsEmpty(r: Range): boolean;

/**
 * Eq instance for Range.
 * Two ranges are equal if they have the same start, end, step, and inclusive flag.
 */
declare const eqRange: Eq<Range>;
/**
 * Ord instance for Range.
 * Compares lexicographically by: start, end, step, inclusive.
 */
declare const ordRange: Ord<Range>;
declare const RangeExt: {
    readonly range: typeof range;
    readonly inclusive: typeof rangeInclusive;
    readonly by: typeof rangeBy;
    readonly reversed: typeof rangeReversed;
    readonly iterator: typeof rangeIterator;
    readonly toArray: typeof rangeToArray;
    readonly forEach: typeof rangeForEach;
    readonly map: typeof rangeMap;
    readonly filter: typeof rangeFilter;
    readonly reduce: typeof rangeReduce;
    readonly contains: typeof rangeContains;
    readonly size: typeof rangeSize;
    readonly first: typeof rangeFirst;
    readonly last: typeof rangeLast;
    readonly isEmpty: typeof rangeIsEmpty;
};

export { type Pair, type Range, RangeExt, type Triple, TupleExt, bimap, both, curryPair, eqPair, eqRange, eqTriple, fst, mapFst, mapSnd, ordPair, ordRange, ordTriple, pair, pairToArray, range, rangeBy, rangeContains, rangeFilter, rangeFirst, rangeForEach, rangeInclusive, rangeIsEmpty, rangeIterator, rangeLast, rangeMap, rangeReduce, rangeReversed, rangeSize, rangeToArray, snd, swap, triple, tripleFirst, tripleMap, tripleSecond, tripleThird, tripleToArray, uncurryPair, unzipPairs, zipToPairs };
