"""
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

from datetime import timedelta
from enum import Enum
from typing import Any, Type

from pypaimon.common.memory_size import MemorySize
from pypaimon.common.time_utils import parse_duration


class OptionsUtils:
    """Utility methods for options conversion and validation."""

    @staticmethod
    def convert_value(value: Any, target_type: Type) -> Any:
        """
        Convert a value to the target type.

        Args:
            value: The value to convert
            target_type: The target type to convert to

        Returns:
            The converted value

        Raises:
            ValueError: If the conversion is not possible
        """
        if value is None:
            return None

        if isinstance(value, target_type):
            return value

        try:
            if issubclass(target_type, Enum):
                return OptionsUtils.convert_to_enum(value, target_type)
        except TypeError:
            pass

        # Handle string conversions
        if target_type == str:
            return OptionsUtils.convert_to_string(value)
        elif target_type == bool:
            return OptionsUtils.convert_to_boolean(value)
        elif target_type == int:
            return OptionsUtils.convert_to_int(value)
        elif target_type == float:
            return OptionsUtils.convert_to_double(value)
        elif target_type == MemorySize:
            return OptionsUtils.convert_to_memory_size(value)
        elif target_type == timedelta:
            return OptionsUtils.convert_to_duration(value)
        else:
            raise ValueError(f"Unsupported type: {target_type}")

    @staticmethod
    def convert_to_string(value: Any) -> str:
        """Convert value to string."""
        return str(value)

    @staticmethod
    def convert_to_boolean(value: Any) -> bool:
        """Convert value to boolean."""
        if isinstance(value, bool):
            return value
        if isinstance(value, str):
            lower_value = value.lower().strip()
            if lower_value in ('true', '1', 'yes', 'on'):
                return True
            elif lower_value in ('false', '0', 'no', 'off'):
                return False
            else:
                raise ValueError(f"Cannot convert '{value}' to boolean")
        elif isinstance(value, (int, float)):
            return bool(value)
        else:
            raise ValueError(f"Cannot convert {type(value)} to boolean")

    @staticmethod
    def convert_to_int(value: Any) -> int:
        """Convert value to integer."""
        if isinstance(value, int):
            return value
        if isinstance(value, str):
            return int(value.strip())
        if isinstance(value, float):
            return int(value)
        raise ValueError(f"Cannot convert {type(value)} to int")

    @staticmethod
    def convert_to_long(value: Any) -> int:
        """Convert value to long (same as int in Python)."""
        return OptionsUtils.convert_to_int(value)

    @staticmethod
    def convert_to_double(value: Any) -> float:
        """Convert value to double (float in Python)."""
        if isinstance(value, float):
            return value
        if isinstance(value, str):
            return float(value.strip())
        if isinstance(value, int):
            return float(value)
        raise ValueError(f"Cannot convert {type(value)} to float")

    @staticmethod
    def convert_to_memory_size(value: Any) -> MemorySize:
        """Convert value to MemorySize."""
        if isinstance(value, MemorySize):
            return value
        if isinstance(value, str):
            return MemorySize.parse(value)
        raise ValueError(f"Cannot convert {type(value)} to MemorySize")

    @staticmethod
    def convert_to_duration(value: Any) -> timedelta:
        if isinstance(value, timedelta):
            return value
        if isinstance(value, str):
            milliseconds = parse_duration(value)
            return timedelta(milliseconds=milliseconds)
        raise ValueError(f"Cannot convert {type(value)} to timedelta")

    @staticmethod
    def convert_to_enum(value: Any, enum_class: Type[Enum]) -> Enum:

        if isinstance(value, enum_class):
            return value

        if isinstance(value, str):
            value_lower = value.lower().strip()
            for enum_member in enum_class:
                if enum_member.value.lower() == value_lower:
                    return enum_member
            try:
                return enum_class[value.upper()]
            except KeyError:
                raise ValueError(
                    f"Cannot convert '{value}' to {enum_class.__name__}. "
                    f"Valid values: {[e.value for e in enum_class]}"
                )
        elif isinstance(value, Enum):
            for enum_member in enum_class:
                if enum_member.value == value.value:
                    return enum_member
            raise ValueError(
                f"Cannot convert {value} (from {type(value).__name__}) to {enum_class.__name__}"
            )
        else:
            raise ValueError(f"Cannot convert {type(value)} to {enum_class.__name__}")
