import datetime as dt
from functools import partial

from . import tcr_print as _m_print
from .tcr_int import hex


class BrainfuckCode(str):
	"""Used in tcr.fmt_iterable() in order to format it as Brainfuck code.

	This will filter out all non-brainfuck characters: `>.<[+-],`.

	This can be used outside of fmt_iterable() to filter characters if needed.
	"""

	def __new__(cls, value):
		return super().__new__(cls, "".join(filter(lambda x: x in ">.<[+-],", value)))


class QuotelessString(str):
	"""Used in tcr.fmt_iterable() in order to format it as a plain text, rather than as `"normal str"`."""


class HexInt(int):
	leading_zeroes: int

	def __new__(cls, value, leading_zeroes=None, prefix=None, **kwargs):
		return super().__new__(cls, value, **kwargs)

	def __init__(self, value, *, leading_zeroes=6, prefix="0x", **_):
		self.leading_zeroes = leading_zeroes
		self.prefix = prefix
		super().__init__()

	def __tcr_fmt__(self, fmt_iterable, **kwargs):
		return fmt_iterable(int(self), **{**kwargs, "int_formatter": partial(hex, leading_zeroes=self.leading_zeroes, prefix=self.prefix)})


class UnreprableString(QuotelessString):
	def __repr__(self) -> str:
		return self


class UnixTimestampInt(int):
	"""Add timezone by assinging the tz attribute after instantiation."""

	def __init__(self, *_, **__) -> None:
		self.tz = None
		super().__init__()

	def _get_as_seconds_unix(self) -> int:
		"""Convert this unix timestamp from any type (seconds, miliseconds, microseconds) to the seconds type by dividing by 1000 each time if it's too large to be the seconds variant."""
		i = int(self)

		while i > 99_999_999_999:  # Convert any milisecond or smaller values to seconds
			i //= 1000

		return i

	def __tcr_fmt__(self, fmt_iterable, **kwargs):
		fromtimestamp_value = self._get_as_seconds_unix()

		while fromtimestamp_value > 99_999_999_999:  # Convert any milisecond or smaller values to seconds
			fromtimestamp_value //= 1000

		lhs = fmt_iterable(dt.datetime.fromtimestamp(fromtimestamp_value, tz=self.tz), **kwargs)
		rhs = fmt_iterable([int(self)], **kwargs)

		return f"{lhs} {rhs}"

	def to_datetime(self, tz: dt.tzinfo | None = None) -> dt.datetime:
		"""Evaluate this unix timestamp into a datetime.datetime object."""
		return dt.datetime.fromtimestamp(self._get_as_seconds_unix(), tz=tz)

	def to_int(self):
		"""Forget that this int is a unix timestamp - You may still use this object in place of an int."""
		return int(self)


class GayString(str):
	"""Used in tcr.fmt_iterable() in order to format it as gay str. Happy pride :3"""  # noqa: D400


class AlwaysTruthyStr(str):
	"""A string that always passes an if check no matter the contents."""

	def __bool__(self):
		return True
