import re
import typing
from decimal import Decimal

from knowit.core import Configurable
from knowit.core import Property
from knowit.utils import round_decimal


class VideoCodec(Configurable[str]):
    """Video Codec handler."""

    @classmethod
    def _extract_key(cls, value) -> str:
        key = value.upper().split('/')[-1]
        if key.startswith('V_'):
            key = key[2:]

        return key.split(' ')[-1]


class VideoDimensions(Property[int]):
    """Dimensions property."""

    def __init__(self, *args: str, dimension='width' or 'height', **kwargs):
        """Initialize the object."""
        super().__init__(*args, **kwargs)
        self.dimension = dimension

    dimensions_re = re.compile(r'(?P<width>\d+)x(?P<height>\d+)')

    def handle(self, value, context) -> typing.Optional[int]:
        """Handle ratio."""
        match = self.dimensions_re.match(value)
        if match:
            match_dict = match.groupdict()
            try:
                value = match_dict[self.dimension]
            except KeyError:
                pass
            else:
                return int(value)

        self.report(value, context)
        return None


class VideoEncoder(Configurable):
    """Video Encoder property."""


class VideoHdrFormat(Configurable):
    """Video HDR Format property."""


class VideoProfile(Configurable[str]):
    """Video Profile property."""

    @classmethod
    def _extract_key(cls, value) -> str:
        return value.upper().split('@')[0]


class VideoProfileLevel(Configurable[str]):
    """Video Profile Level property."""

    @classmethod
    def _extract_key(cls, value) -> typing.Union[str, bool]:
        values = str(value).upper().split('@')
        if len(values) > 1:
            value = values[1]
            return value

        # There's no level, so don't warn or report it
        return False


class VideoProfileTier(Configurable[str]):
    """Video Profile Tier property."""

    @classmethod
    def _extract_key(cls, value) -> typing.Union[str, bool]:
        values = str(value).upper().split('@')
        if len(values) > 2:
            return values[2]

        # There's no tier, so don't warn or report it
        return False


class Ratio(Property[Decimal]):
    """Ratio property."""

    def __init__(self, *args: str, unit=None, **kwargs):
        """Initialize the object."""
        super().__init__(*args, **kwargs)
        self.unit = unit

    ratio_re = re.compile(r'(?P<width>\d+)[:/](?P<height>\d+)')

    def handle(self, value, context) -> typing.Optional[Decimal]:
        """Handle ratio."""
        match = self.ratio_re.match(value)
        if match:
            width, height = match.groups()
            if (width, height) == ('0', '1'):  # identity
                return Decimal('1.0')

            if height:
                result = round_decimal(Decimal(width) / Decimal(height), min_digits=1, max_digits=3)
                if self.unit:
                    result *= self.unit

                return result

        self.report(value, context)
        return None


class ScanType(Configurable[str]):
    """Scan Type property."""
