"""
CSSL Data Types - Advanced container types for CSO Service Script Language

Types:
- datastruct<T>: Universal container (lazy declarator) - can hold any type
- shuffled<T>: Unorganized fast storage for multiple returns
- iterator<T>: Advanced iterator with programmable tasks
- combo<T>: Filter/search spaces for open parameter matching
- dataspace<T>: SQL/data storage container
- openquote<T>: SQL openquote container
"""

from typing import Any, Dict, List, Optional, Callable, Union, TypeVar, Generic
from dataclasses import dataclass, field
import copy


T = TypeVar('T')


class DataStruct(list):
    """Universal container - lazy declarator that can hold any type.

    Like a vector but more flexible. Can hold strings, ints, floats,
    objects, etc. at the cost of performance.

    Usage:
        datastruct<dynamic> myData;
        myData +<== someValue;
        myData.content()  # Returns all elements
    """

    def __init__(self, element_type: str = 'dynamic'):
        super().__init__()
        self._element_type = element_type
        self._metadata: Dict[str, Any] = {}

    def content(self) -> list:
        """Return all elements as a list"""
        return list(self)

    def add(self, item: Any) -> 'DataStruct':
        """Add an item to the datastruct"""
        self.append(item)
        return self

    def remove_where(self, predicate: Callable[[Any], bool]) -> 'DataStruct':
        """Remove items matching predicate"""
        to_remove = [item for item in self if predicate(item)]
        for item in to_remove:
            self.remove(item)
        return self

    def find_where(self, predicate: Callable[[Any], bool]) -> Optional[Any]:
        """Find first item matching predicate"""
        for item in self:
            if predicate(item):
                return item
        return None

    def convert(self, target_type: type) -> Any:
        """Convert first element to target type"""
        if len(self) > 0:
            return target_type(self[0])
        return None


class Shuffled(list):
    """Unorganized fast storage for multiple returns.

    Stores data unorganized for fast and efficient access.
    Supports receiving multiple return values from functions.

    Usage:
        shuffled<string> results;
        results +<== someFunc();  # Catches all returns
        results.read()  # Returns all content as list
    """

    def __init__(self, element_type: str = 'dynamic'):
        super().__init__()
        self._element_type = element_type

    def read(self) -> list:
        """Return all content as a list"""
        return list(self)

    def collect(self, func: Callable, *args) -> 'Shuffled':
        """Collect all returns from a function"""
        result = func(*args)
        if isinstance(result, (list, tuple)):
            self.extend(result)
        else:
            self.append(result)
        return self


class Iterator:
    """Advanced iterator with programmable tasks.

    Provides iterator positions within a data container with
    the ability to attach tasks (functions) to iterators.

    Usage:
        iterator<int, 16> Map;  # Create 16-element iterator space
        Map::iterator::set(0, 5);  # Set iterator 0 to position 5
        Map::iterator::task(0, myFunc);  # Attach task to iterator
    """

    def __init__(self, element_type: str = 'int', size: int = 16):
        self._element_type = element_type
        self._size = size
        self._data: List[Any] = [None] * size
        self._iterators: Dict[int, int] = {0: 0, 1: 1}  # Default: 2 iterators at positions 0 and 1
        self._tasks: Dict[int, Callable] = {}

    def insert(self, index: int, value: Any) -> 'Iterator':
        """Insert value at index"""
        if 0 <= index < self._size:
            self._data[index] = value
        return self

    def fill(self, value: Any) -> 'Iterator':
        """Fill all positions with value"""
        self._data = [value] * self._size
        return self

    def at(self, index: int) -> Any:
        """Get value at index"""
        if 0 <= index < self._size:
            return self._data[index]
        return None

    def is_all(self, check_value: bool) -> bool:
        """Check if all values are 1 (True) or 0 (False)"""
        expected = 1 if check_value else 0
        return all(v == expected for v in self._data if v is not None)

    def end(self) -> int:
        """Return last index"""
        return self._size - 1

    class IteratorControl:
        """Static methods for iterator control"""

        @staticmethod
        def set(iterator_obj: 'Iterator', iterator_id: int, position: int):
            """Set iterator position"""
            iterator_obj._iterators[iterator_id] = position

        @staticmethod
        def move(iterator_obj: 'Iterator', iterator_id: int, steps: int):
            """Move iterator by steps"""
            if iterator_id in iterator_obj._iterators:
                iterator_obj._iterators[iterator_id] += steps

        @staticmethod
        def insert(iterator_obj: 'Iterator', iterator_id: int, value: Any):
            """Insert value at current iterator position"""
            if iterator_id in iterator_obj._iterators:
                pos = iterator_obj._iterators[iterator_id]
                if 0 <= pos < iterator_obj._size:
                    iterator_obj._data[pos] = value

        @staticmethod
        def pop(iterator_obj: 'Iterator', iterator_id: int):
            """Delete value at current iterator position"""
            if iterator_id in iterator_obj._iterators:
                pos = iterator_obj._iterators[iterator_id]
                if 0 <= pos < iterator_obj._size:
                    iterator_obj._data[pos] = None

        @staticmethod
        def task(iterator_obj: 'Iterator', iterator_id: int, func: Callable):
            """Attach a task function to iterator"""
            iterator_obj._tasks[iterator_id] = func

        @staticmethod
        def dtask(iterator_obj: 'Iterator', iterator_id: int):
            """Clear task from iterator"""
            if iterator_id in iterator_obj._tasks:
                del iterator_obj._tasks[iterator_id]

        @staticmethod
        def run_task(iterator_obj: 'Iterator', iterator_id: int):
            """Run the task at current iterator position"""
            if iterator_id in iterator_obj._tasks and iterator_id in iterator_obj._iterators:
                pos = iterator_obj._iterators[iterator_id]
                task = iterator_obj._tasks[iterator_id]
                # Create a position wrapper
                class IteratorPos:
                    def __init__(self, data, idx):
                        self._data = data
                        self._idx = idx
                    def read(self):
                        return self._data[self._idx]
                    def write(self, value):
                        self._data[self._idx] = value

                task(IteratorPos(iterator_obj._data, pos))


class Combo:
    """Filter/search space for open parameter matching.

    Creates a search/filter space that can match parameters
    based on filter databases and similarity.

    Usage:
        combo<open&string> nameSpace;
        nameSpace +<== [combo::filterdb] filterDB;
        special_name = OpenFind(&nameSpace);
    """

    def __init__(self, element_type: str = 'dynamic'):
        self._element_type = element_type
        self._filterdb: List[Any] = []
        self._blocked: List[Any] = []
        self._data: List[Any] = []
        self._like_pattern: Optional[str] = None

    @property
    def filterdb(self) -> List[Any]:
        return self._filterdb

    @filterdb.setter
    def filterdb(self, value: List[Any]):
        self._filterdb = value

    @property
    def blocked(self) -> List[Any]:
        return self._blocked

    @blocked.setter
    def blocked(self, value: List[Any]):
        self._blocked = value

    def like(self, pattern: str) -> 'Combo':
        """Set similarity pattern (94-100% match)"""
        self._like_pattern = pattern
        return self

    def matches(self, value: Any) -> bool:
        """Check if value matches combo criteria"""
        # Check if blocked
        if value in self._blocked:
            return False

        # Check filterdb if present
        if self._filterdb:
            if value not in self._filterdb:
                return False

        # Check like pattern if present
        if self._like_pattern and isinstance(value, str):
            similarity = self._calculate_similarity(value, self._like_pattern)
            if similarity < 0.94:
                return False

        return True

    def _calculate_similarity(self, s1: str, s2: str) -> float:
        """Calculate string similarity (simple Levenshtein-based)"""
        if s1 == s2:
            return 1.0
        if not s1 or not s2:
            return 0.0

        # Simple character-based similarity
        s1_lower = s1.lower()
        s2_lower = s2.lower()

        matching = sum(c1 == c2 for c1, c2 in zip(s1_lower, s2_lower))
        return matching / max(len(s1), len(s2))

    def find_match(self, items: List[Any]) -> Optional[Any]:
        """Find first matching item from list"""
        for item in items:
            if self.matches(item):
                return item
        return None


class DataSpace(dict):
    """SQL/data storage container for structured data.

    Used for SQL table definitions and structured data storage.

    Usage:
        dataspace<sql::table> table = { ... };
        @Sql.Structured(&table);
    """

    def __init__(self, space_type: str = 'dynamic'):
        super().__init__()
        self._space_type = space_type
        self._sections: Dict[str, Any] = {}

    def content(self) -> dict:
        """Return all content"""
        return dict(self)

    def section(self, name: str, *types) -> 'DataSpace':
        """Create a section with specified types"""
        self._sections[name] = {
            'types': types,
            'data': []
        }
        return self


class OpenQuote:
    """SQL openquote container for organized data handling.

    Creates a datastruct together with sql::db.oqt() for easy
    data organization and retrieval.

    Usage:
        openquote<datastruct<dynamic>&@sql::db.oqt(@db)> Queue;
        Queue.save("Section", "data1", "data2", 123);
        Queue.where(Section="value", KEY="match");
    """

    def __init__(self, db_reference: Any = None):
        self._data: List[Dict[str, Any]] = []
        self._db_ref = db_reference

    def save(self, section: str, *values) -> 'OpenQuote':
        """Save data to a section"""
        self._data.append({
            'section': section,
            'values': list(values)
        })
        return self

    def where(self, **kwargs) -> Optional[Any]:
        """Find data matching criteria"""
        for entry in self._data:
            if all(entry.get(k) == v or (k == 'Section' and entry.get('section') == v)
                   for k, v in kwargs.items()):
                return entry
        return None

    def all(self) -> List[Dict[str, Any]]:
        """Return all data"""
        return self._data


def OpenFind(combo_or_type: Union[Combo, type], index: int = 0) -> Optional[Any]:
    """Find open parameter by type or combo space.

    Usage:
        string name = OpenFind<string>(0);  # Find string at index 0
        string special = OpenFind(&@comboSpace);  # Find by combo
    """
    if isinstance(combo_or_type, Combo):
        # Find by combo space
        return combo_or_type.find_match([])  # Would need open params context
    elif isinstance(combo_or_type, type):
        # Find by type at index - needs open params context
        pass
    return None


# Type factory functions for CSSL
def create_datastruct(element_type: str = 'dynamic') -> DataStruct:
    return DataStruct(element_type)

def create_shuffled(element_type: str = 'dynamic') -> Shuffled:
    return Shuffled(element_type)

def create_iterator(element_type: str = 'int', size: int = 16) -> Iterator:
    return Iterator(element_type, size)

def create_combo(element_type: str = 'dynamic') -> Combo:
    return Combo(element_type)

def create_dataspace(space_type: str = 'dynamic') -> DataSpace:
    return DataSpace(space_type)

def create_openquote(db_ref: Any = None) -> OpenQuote:
    return OpenQuote(db_ref)


__all__ = [
    'DataStruct', 'Shuffled', 'Iterator', 'Combo', 'DataSpace', 'OpenQuote',
    'OpenFind',
    'create_datastruct', 'create_shuffled', 'create_iterator',
    'create_combo', 'create_dataspace', 'create_openquote'
]
