import uuid
from datetime import datetime, UTC
from io import BytesIO

import pandas as pd

from bb_integrations_lib.models.pipeline_structs import PipelineContext
from bb_integrations_lib.protocols.pipelines import Step, ParserBase
from bb_integrations_lib.shared.model import RawData


class BBDParseOrder(Step):

    def __init__(self,
                 step_key: str | None = uuid.uuid4().hex,
                 file_base_name: str = "Gravitate_Order_Export",
                 parser: ParserBase | None = None,
                 parser_kwargs: dict | None = None,
                 *args,
                 **kwargs):
        super().__init__(*args, **kwargs)
        if self.pipeline_context is None:
            self.pipeline_context = PipelineContext()
        self.file_base_name = file_base_name
        self.step_key = step_key

        if parser:
            self.custom_parser: type[ParserBase] = parser
            self.custom_parser_kwargs = parser_kwargs

    def describe(self):
        return "Parse order bols and drops data into export format"

    async def execute(self, data: list[dict]) -> RawData | list[RawData]:
        if hasattr(self, "custom_parser"):
            parser = self.custom_parser(**self.custom_parser_kwargs)

            rows, processed, errors = await parser.parse(data)
            self.pipeline_context.extra_data.setdefault("errored_orders", []).extend(errors)
            self.pipeline_context.extra_data.setdefault("processed_orders", []).extend(processed)
            if rows and isinstance(rows[0], RawData):
                return rows
            return self.to_raw_data(rows)
        else:
            return self.to_raw_data(data)

    def to_raw_data(self, data: list[dict]) -> RawData:
        now = datetime.now(UTC)
        file_name = f"{self.file_base_name}_{now.strftime('%Y%m%d%H%M%S')}.csv"
        if not data:
            return RawData(file_name=file_name, data=None)
        df = pd.DataFrame(data)
        csv_str = df.to_csv(index=False).encode("utf-8")
        return RawData(file_name=file_name, data=BytesIO(csv_str))

