import { TSchema } from '@evolution-sdk/evolution';
import { divideOnChainCompatible } from '../utils/bigint-utils';

export const RationalSchema = TSchema.Struct({
  numerator: TSchema.Integer,
  denominator: TSchema.Integer,
});

export type Rational = typeof RationalSchema.Type;

export const rationalZero: Rational = { numerator: 0n, denominator: 1n };

export function rationalFromInt(a: bigint): Rational {
  return { numerator: a, denominator: 1n };
}

export function rationalFloor(a: Rational): bigint {
  return divideOnChainCompatible(a.numerator, a.denominator);
}

export function rationalCeil(a: Rational): bigint {
  const intDiv = a.numerator / a.denominator;
  return a.numerator % a.denominator > 0n ? intDiv + 1n : intDiv;
}

export function rationalNegate(a: Rational): Rational {
  return { numerator: -a.numerator, denominator: a.denominator };
}

export function rationalAdd(a: Rational, b: Rational): Rational {
  return {
    numerator: a.numerator * b.denominator + b.numerator * a.denominator,
    denominator: a.denominator * b.denominator,
  };
}

export function rationalSub(a: Rational, b: Rational): Rational {
  return {
    numerator: a.numerator * b.denominator - b.numerator * a.denominator,
    denominator: a.denominator * b.denominator,
  };
}

export function rationalMul(a: Rational, b: Rational): Rational {
  return {
    numerator: a.numerator * b.numerator,
    denominator: a.denominator * b.denominator,
  };
}

export function rationalDiv(a: Rational, b: Rational): Rational {
  if (b.numerator === 0n) throw new Error('Cannot divide by zero.');
  return {
    numerator: a.numerator * b.denominator,
    denominator: a.denominator * b.numerator,
  };
}

export function rationalToFloat(a: Rational): number {
  return Number(a.numerator) / Number(a.denominator);
}
