from typing import Final, List, Optional, TypedDict

from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent
from moto.stepfunctions.parser.asl.component.state.exec.state_map.item_reader.reader_config.csv_header_location import (
    CSVHeaderLocation,
)
from moto.stepfunctions.parser.asl.component.state.exec.state_map.item_reader.reader_config.csv_headers import (
    CSVHeaders,
)
from moto.stepfunctions.parser.asl.component.state.exec.state_map.item_reader.reader_config.input_type import (
    InputType,
)
from moto.stepfunctions.parser.asl.component.state.exec.state_map.item_reader.reader_config.max_items_decl import (
    MaxItems,
    MaxItemsDecl,
)
from moto.stepfunctions.parser.asl.eval.environment import Environment


class InputTypeOutput(str):
    CSV = "CSV"
    JSON = "JSON"


class CSVHeaderLocationOutput(str):
    FIRST_ROW = "FIRST_ROW"
    GIVEN = "GIVEN"


CSVHeadersOutput = List[str]
MaxItemsValueOutput = int


class ReaderConfigOutput(TypedDict):
    InputType: InputTypeOutput
    CSVHeaderLocation: CSVHeaderLocationOutput
    CSVHeaders: Optional[CSVHeadersOutput]
    MaxItemsValue: MaxItemsValueOutput


class ReaderConfig(EvalComponent):
    input_type: Final[InputType]
    max_items_decl: Final[MaxItemsDecl]
    csv_header_location: Final[CSVHeaderLocation]
    csv_headers: Optional[CSVHeaders]

    def __init__(
        self,
        input_type: InputType,
        csv_header_location: CSVHeaderLocation,
        csv_headers: Optional[CSVHeaders],
        max_items_decl: Optional[MaxItemsDecl],
    ):
        self.input_type = input_type
        self.max_items_decl = max_items_decl or MaxItems()
        self.csv_header_location = csv_header_location
        self.csv_headers = csv_headers
        # TODO: verify behaviours:
        #  - csv fields are declared with json input type
        #  - headers are declared with first_fow location set

    def _eval_body(self, env: Environment) -> None:
        self.max_items_decl.eval(env=env)
        max_items_value: int = env.stack.pop()

        reader_config_output = ReaderConfigOutput(
            InputType=InputTypeOutput(self.input_type.input_type_value),
            MaxItemsValue=max_items_value,
        )
        if self.csv_header_location:
            reader_config_output["CSVHeaderLocation"] = (
                self.csv_header_location.csv_header_location_value.value
            )
        if self.csv_headers:
            reader_config_output["CSVHeaders"] = self.csv_headers.header_names
        env.stack.append(reader_config_output)
