# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_core.ipynb.

# %% auto 0
__all__ = ['AnyQ', 'IntQ', 'BoolQ', 'BoolFunc', 'isany', 'key1st', 'idx1st', 'ropts']

# %% ../nbs/00_core.ipynb 4
import itertools
from dataclasses import dataclass, field
from typing import Any, List, Union, Callable, Optional, TypeAlias, TypeGuard

AnyQ: TypeAlias = Optional[Any]
IntQ: TypeAlias = Optional[int]
BoolQ: TypeAlias = Optional[bool]
BoolFunc: TypeAlias = Callable[[Any], bool]

# %% ../nbs/00_core.ipynb 7
def isany(x: Any, *args, **kwargs) -> bool:
    return x is not None

# %% ../nbs/00_core.ipynb 8
def key1st(dct: dict, keys: list, flag: BoolFunc = isany, default: AnyQ = None, fallback: BoolQ = True,) -> AnyQ:
    gen = (dct[key] for key in keys if key in dct and flag(dct[key]))
    dflt = default or (dct.get(keys[-1], None) if (keys and fallback) else None)
    return next(gen, dflt)

# %% ../nbs/00_core.ipynb 9
def idx1st(*args, flag: BoolFunc = isany, fallback: BoolQ = True, default: AnyQ = None) -> IntQ:
    gen = (i for i in range(len(args)) if flag(args[i]))
    dflt = default or (len(args) - 1 if (args and fallback) else None)
    return next(gen, dflt)

# %% ../nbs/00_core.ipynb 11
# @dataclass
class ropts(tuple):
    '''Ranked Options (ROpts).'''
    def __new__(cls, opts: list):
        return super(ropts, cls).__new__(cls, tuple(opts))
        
    def __len__(self) -> int: 
        return super().__len__()
    
    def __iter__(self): 
        return super().__iter__()
    
    def __getitem__(self, key: int) -> str: 
        return super().__getitem__(key)
    
    
    @classmethod
    def optkey(cls, opt: AnyQ) -> str:
        '''Convert an option to a dictionary key.'''
        return str(opt)

    @classmethod
    def valkey(cls, opt: str) -> str: 
        '''Get the "value key" for a given option i.e. `f'{opt}val'`.'''
        return f'{opt}val'
        
    @classmethod
    def optkeys(cls, opt: AnyQ) -> tuple:
        '''Create any number of dictionary keys to lookup for a given option.'''
        return cls.optkey(opt), cls.valkey(opt)
    
    @classmethod
    def makekeys(cls, opts: list) -> list:
        '''Make a list of keys based on a list of options.'''
        return [cls.optkey(opt) for opt in opts]

    @classmethod
    def allkeys(cls, opts: list) -> list:
        '''Make a list of keys corresponding to each option based on a list of options.'''
        return list(itertools.chain(*[cls.optkeys(opt) for opt in opts]))

    
    @classmethod
    def getval(cls, opts: list, **kwargs) -> AnyQ:
        '''Get the value for a given list of options and keyword arguments.'''
        order = cls.allkeys(opts)
        value = key1st(kwargs, order)
        return value

    @classmethod
    def getidx(cls, opt: str, opts: list) -> IntQ:        
        return idx1st(*opts, flag=lambda x: x == opt, fallback=False)
    
    @classmethod
    def getrank(cls, opt: Union[int, str], opts: list, **kwargs) -> AnyQ:
        '''Get the value based on the provided rank and keyword arguments.'''
        rank = opt if isinstance(opt, int) else cls.getidx(opt, opts)
        if (rank is None or (rank < 0 or len(opts) <= rank)): return None
        return cls.getval([opts[rank]], **kwargs)
    
    def get(self, **kwargs: Any) -> AnyQ:
        '''Get the value based on the provided options and keyword arguments.'''
        return self.getval(self, **kwargs)
    
    def idx(self, opt: str) -> IntQ:
        '''Get the integer rank based on the provided option.'''
        return self.getidx(opt, self)
    
    def rnk(self, opt: Union[int, str], **kwargs) -> AnyQ:
        return self.getrank(opt, self, **kwargs)

    def __repr__(self) -> str:
        supstr = super().__repr__()
        return f'ropts{supstr}'
