from dataclasses import fields, is_dataclass
from typing import *


def dataclass_from_flat_list(cls: type, values: Tuple[Any, ...]) -> Any:
    if not is_dataclass(cls):
        raise TypeError(f"{cls} is not a dataclass")

    idx = 0
    init_values = {}
    for field in fields(cls):
        if is_dataclass(field.type):
            inner_values = [values[idx + i] for i in range(len(fields(field.type)))]
            init_values[field.name] = field.type(*inner_values)
            idx += len(inner_values)
        else:
            if idx >= len(values):
                raise IndexError(
                    f"Expected more values for dataclass {cls}. Current index: {idx}, values length: {len(values)}"
                )
            value = values[idx]
            init_values[field.name] = value
            idx += 1
    return cls(**init_values)


def dataclasses_from_flat_list(
    classes_mapping: List[type], values: Tuple[Any, ...]
) -> List[Any]:
    instances = []
    idx = 0
    for cls in classes_mapping:
        num_fields = sum(
            len(fields(field.type)) if is_dataclass(field.type) else 1
            for field in fields(cls)
        )
        instance = dataclass_from_flat_list(cls, values[idx : idx + num_fields])
        instances.append(instance)
        idx += num_fields
    assert [
        isinstance(i, t) for i, t in zip(instances, classes_mapping)
    ], "Instances should match types"
    return instances
