import {
  toSafeBooleanOrNull,
  toSafeIsoDateOrNull,
  toSafeIntOrNull,
  toSafeNumberOrNull,
  toSafeString,
  toSafeStringOrNull,
} from './safe-parse.util';
import { safeParseFixtures } from '@test-fixtures/common/safe-parse.fixture';

describe('safe-parse utils', () => {
  describe('toSafeString', () => {
    it('returns fallback for nullish', () => {
      expect(toSafeString(safeParseFixtures.toSafeString.nullInput)).toBe(
        safeParseFixtures.toSafeString.expectedEmpty,
      );
      expect(
        toSafeString(
          safeParseFixtures.toSafeString.undefinedInput,
          safeParseFixtures.toSafeString.fallback,
        ),
      ).toBe(safeParseFixtures.toSafeString.fallback);
    });

    it('returns string as-is', () => {
      expect(toSafeString(safeParseFixtures.toSafeString.stringInput)).toBe(
        safeParseFixtures.toSafeString.stringInput,
      );
    });

    it('stringifies number/boolean/bigint', () => {
      expect(toSafeString(safeParseFixtures.toSafeString.numberInput)).toBe(
        String(safeParseFixtures.toSafeString.numberInput),
      );
      expect(toSafeString(safeParseFixtures.toSafeString.booleanInput)).toBe(
        String(safeParseFixtures.toSafeString.booleanInput),
      );
      expect(toSafeString(safeParseFixtures.toSafeString.bigintInput)).toBe(
        String(safeParseFixtures.toSafeString.bigintInput),
      );
    });

    it('returns ISO string for Date', () => {
      expect(toSafeString(safeParseFixtures.toSafeString.dateInput)).toBe(
        safeParseFixtures.toSafeString.dateExpected,
      );
    });

    it('returns fallback for objects', () => {
      expect(
        toSafeString(
          safeParseFixtures.toSafeString.objectInput,
          safeParseFixtures.toSafeString.objectFallback,
        ),
      ).toBe(safeParseFixtures.toSafeString.objectFallback);
    });
  });

  describe('toSafeIsoDateOrNull', () => {
    it('returns null for nullish', () => {
      expect(
        toSafeIsoDateOrNull(safeParseFixtures.toSafeIsoDateOrNull.nullInput),
      ).toBeNull();
      expect(
        toSafeIsoDateOrNull(
          safeParseFixtures.toSafeIsoDateOrNull.undefinedInput,
        ),
      ).toBeNull();
    });

    it('returns ISO string for Date', () => {
      expect(
        toSafeIsoDateOrNull(safeParseFixtures.toSafeIsoDateOrNull.dateInput),
      ).toBe(safeParseFixtures.toSafeIsoDateOrNull.dateExpected);
    });

    it('returns string as-is', () => {
      expect(
        toSafeIsoDateOrNull(safeParseFixtures.toSafeIsoDateOrNull.stringInput),
      ).toBe(safeParseFixtures.toSafeIsoDateOrNull.stringExpected);
    });

    it('returns null for non-string values', () => {
      expect(
        toSafeIsoDateOrNull(safeParseFixtures.toSafeIsoDateOrNull.numberInput),
      ).toBeNull();
    });
  });

  describe('toSafeStringOrNull', () => {
    it('returns null for nullish', () => {
      expect(
        toSafeStringOrNull(safeParseFixtures.toSafeStringOrNull.nullInput),
      ).toBeNull();
      expect(
        toSafeStringOrNull(safeParseFixtures.toSafeStringOrNull.undefinedInput),
      ).toBeNull();
    });

    it('returns trimmed string when not empty', () => {
      expect(
        toSafeStringOrNull(safeParseFixtures.toSafeStringOrNull.trimmedInput),
      ).toBe(safeParseFixtures.toSafeStringOrNull.trimmedExpected);
    });

    it('returns null for empty/whitespace strings', () => {
      expect(
        toSafeStringOrNull(safeParseFixtures.toSafeStringOrNull.emptyInput),
      ).toBeNull();
      expect(
        toSafeStringOrNull(
          safeParseFixtures.toSafeStringOrNull.whitespaceInput,
        ),
      ).toBeNull();
    });
  });

  describe('toSafeNumberOrNull', () => {
    it('returns null for nullish', () => {
      expect(
        toSafeNumberOrNull(safeParseFixtures.toSafeNumberOrNull.nullInput),
      ).toBeNull();
      expect(
        toSafeNumberOrNull(safeParseFixtures.toSafeNumberOrNull.undefinedInput),
      ).toBeNull();
    });

    it('returns number when finite', () => {
      expect(
        toSafeNumberOrNull(safeParseFixtures.toSafeNumberOrNull.numberInput),
      ).toBe(safeParseFixtures.toSafeNumberOrNull.numberExpected);
      expect(
        toSafeNumberOrNull(safeParseFixtures.toSafeNumberOrNull.negativeInput),
      ).toBe(safeParseFixtures.toSafeNumberOrNull.negativeExpected);
    });

    it('returns null for NaN', () => {
      expect(
        toSafeNumberOrNull(safeParseFixtures.toSafeNumberOrNull.nanInput),
      ).toBeNull();
    });

    it('parses numeric strings', () => {
      expect(
        toSafeNumberOrNull(
          safeParseFixtures.toSafeNumberOrNull.numericStringInput,
        ),
      ).toBe(safeParseFixtures.toSafeNumberOrNull.numericStringExpected);
      expect(
        toSafeNumberOrNull(
          safeParseFixtures.toSafeNumberOrNull.floatStringInput,
        ),
      ).toBe(safeParseFixtures.toSafeNumberOrNull.floatStringExpected);
    });

    it('returns null for invalid strings', () => {
      expect(
        toSafeNumberOrNull(
          safeParseFixtures.toSafeNumberOrNull.invalidStringInput,
        ),
      ).toBeNull();
    });
  });

  describe('toSafeIntOrNull', () => {
    it('returns null for nullish', () => {
      expect(
        toSafeIntOrNull(safeParseFixtures.toSafeIntOrNull.nullInput),
      ).toBeNull();
      expect(
        toSafeIntOrNull(safeParseFixtures.toSafeIntOrNull.undefinedInput),
      ).toBeNull();
    });

    it('returns truncated integers', () => {
      expect(
        toSafeIntOrNull(safeParseFixtures.toSafeIntOrNull.floatInput),
      ).toBe(safeParseFixtures.toSafeIntOrNull.floatExpected);
      expect(
        toSafeIntOrNull(safeParseFixtures.toSafeIntOrNull.negativeFloatInput),
      ).toBe(safeParseFixtures.toSafeIntOrNull.negativeFloatExpected);
    });

    it('parses numeric strings and truncates', () => {
      expect(
        toSafeIntOrNull(safeParseFixtures.toSafeIntOrNull.floatStringInput),
      ).toBe(safeParseFixtures.toSafeIntOrNull.floatStringExpected);
    });

    it('returns null for invalid strings', () => {
      expect(
        toSafeIntOrNull(safeParseFixtures.toSafeIntOrNull.invalidStringInput),
      ).toBeNull();
    });
  });

  describe('toSafeBooleanOrNull', () => {
    it('returns null for nullish', () => {
      expect(
        toSafeBooleanOrNull(safeParseFixtures.toSafeBooleanOrNull.nullInput),
      ).toBeNull();
      expect(
        toSafeBooleanOrNull(
          safeParseFixtures.toSafeBooleanOrNull.undefinedInput,
        ),
      ).toBeNull();
    });

    it('returns boolean as-is', () => {
      expect(
        toSafeBooleanOrNull(safeParseFixtures.toSafeBooleanOrNull.trueInput),
      ).toBe(true);
      expect(
        toSafeBooleanOrNull(safeParseFixtures.toSafeBooleanOrNull.falseInput),
      ).toBe(false);
    });

    it('converts numbers', () => {
      expect(
        toSafeBooleanOrNull(safeParseFixtures.toSafeBooleanOrNull.zeroInput),
      ).toBe(safeParseFixtures.toSafeBooleanOrNull.zeroExpected);
      expect(
        toSafeBooleanOrNull(safeParseFixtures.toSafeBooleanOrNull.oneInput),
      ).toBe(safeParseFixtures.toSafeBooleanOrNull.oneExpected);
      expect(
        toSafeBooleanOrNull(
          safeParseFixtures.toSafeBooleanOrNull.negativeInput,
        ),
      ).toBe(safeParseFixtures.toSafeBooleanOrNull.negativeExpected);
    });

    it('parses common string values', () => {
      expect(
        toSafeBooleanOrNull(
          safeParseFixtures.toSafeBooleanOrNull.trueStringInput,
        ),
      ).toBe(safeParseFixtures.toSafeBooleanOrNull.trueStringExpected);
      expect(
        toSafeBooleanOrNull(
          safeParseFixtures.toSafeBooleanOrNull.falseStringInput,
        ),
      ).toBe(safeParseFixtures.toSafeBooleanOrNull.falseStringExpected);
      expect(
        toSafeBooleanOrNull(
          safeParseFixtures.toSafeBooleanOrNull.oneStringInput,
        ),
      ).toBe(safeParseFixtures.toSafeBooleanOrNull.oneStringExpected);
      expect(
        toSafeBooleanOrNull(
          safeParseFixtures.toSafeBooleanOrNull.zeroStringInput,
        ),
      ).toBe(safeParseFixtures.toSafeBooleanOrNull.zeroStringExpected);
    });

    it('returns null for other strings', () => {
      expect(
        toSafeBooleanOrNull(
          safeParseFixtures.toSafeBooleanOrNull.invalidStringInput,
        ),
      ).toBeNull();
    });
  });
});
