<?php

namespace Planaday\Utility\DataFilters;

class TypeValidator {
	/**
	 * @param mixed $data
	 * @param string|null $invalidMessage
	 *
	 * @return string|null
	 * @throws InvalidException
	 */
	public function str (mixed $data, ?string $invalidMessage = null):?string {
		if ($data === null) return null;
		if (is_string($data) || is_scalar($data) || (is_object($data) && method_exists($data, '__toString'))) return (string)$data;


		throw new InvalidException($invalidMessage ?? 'expected a string but did not receive a string');
	}

	/**
	 * @param mixed $data
	 * @param string|null $invalidMessage
	 *
	 * @return int|null
	 * @throws InvalidException
	 */
	public function int (mixed $data, ?string $invalidMessage = null):?int {
		if ($data === null) return null;
		$filtered = filter_var($data, FILTER_VALIDATE_INT);
		if ($filtered !== false) return $filtered;

		throw new InvalidException($invalidMessage ?? 'expected an int but did not receive an int');
	}

	/**
	 * @param mixed $data
	 * @param string|null $invalidMessage
	 *
	 * @return float|null
	 * @throws InvalidException
	 */
	public function float (mixed $data, ?string $invalidMessage = null):?float {
		if ($data === null) return null;
		$filtered = filter_var($data, FILTER_VALIDATE_FLOAT);
		if ($filtered !== false) return $filtered;

		throw new InvalidException($invalidMessage ?? 'expected a float but did not receive a float');
	}

	/**
	 * @param mixed $data
	 * @param string|null $invalidMessage
	 *
	 * @return bool|null
	 * @throws InvalidException
	 */
	public function bool (mixed $data, ?string $invalidMessage = null):?bool {
		if ($data === null) return null;
		$filtered = filter_var($data, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
		if ($filtered !== null) return $filtered;


		throw new InvalidException($invalidMessage ?? 'expected a bool but did not receive a bool');
	}

	/**
	 * @param mixed $data
	 * @param string|null $invalidMessage
	 *
	 * @return array<mixed>|null
	 * @throws InvalidException
	 */
	public function array (mixed $data, ?string $invalidMessage = null):?array {
		if ($data === null) return null;
		if (is_array($data)) return $data;

		throw new InvalidException($invalidMessage ?? 'expected an array but did not receive an array');
	}

	/**
	 * @param mixed $data
	 * @param string|null $invalidMessage
	 * @param bool $canBeInt
	 *
	 * @return int|null
	 * @throws InvalidException
	 */
	public function time (mixed $data, ?string $invalidMessage = null, bool $canBeInt = true):?int {
		if ($data === null) return null;
		if ($canBeInt && filter_var($data, FILTER_VALIDATE_INT) !== false) return $this->int($data);

		$strtotime = strtotime($this->str($data) ?? '');
		if ($strtotime !== false) return $strtotime;

		throw new InvalidException($invalidMessage ?? 'expected a time but did not receive a time');
	}
}