import string
from typing import Any, List

from llm_compact_serializer.core.serializer import DynamicSerializer
from llm_compact_serializer.domain.schema import CompactSchema, FieldConfig


class PromptBuilder:
    _PROTOCOL_SIGNATURE = "[COMPACT_HIERARCHICAL_PROTOCOL]"

    def __init__(self, schema: CompactSchema):
        self.schema = schema
        self.serializer = DynamicSerializer(schema)

    def _get_field_index(self, prefix: str, index: int, is_complex: bool) -> str:
        """
        Generates indices like 1a, 1b (simple) or 1.1, 1.2 (complex).
        """
        if is_complex:
            # Sub-objects increase numerical depth: 1.1, 1.2
            return f"{prefix}.{index + 1}"
        else:
            # Primitives get letters: 1a, 1b
            # We map 0 -> a, 1 -> b...
            letter = string.ascii_lowercase[index % 26]
            return f"{prefix}{letter}"

    def _describe_schema_recursive(
        self, schema: CompactSchema, prefix: str
    ) -> List[str]:
        lines = []

        # Split fields into simple vs complex to manage counters if strictly needed,
        # but usually we just iterate in order.
        # User requirement:
        # 1a = simple
        # 1.1 = complex

        simple_counter = 0
        complex_counter = 0

        for field in schema.fields:
            is_complex = field.nested_schema is not None

            # Determine Label
            if is_complex:
                label = f"{prefix}.{complex_counter + 1}"
                complex_counter += 1
            else:
                letter = string.ascii_lowercase[simple_counter % 26]
                label = f"{prefix}{letter}"
                simple_counter += 1

            # Determine Indicators
            type_indicator = "*" if field.is_list else ""

            # Generate Description Line
            lines.append(f"# {label}{type_indicator} = {field.source_name}")

            # Recurse if complex
            if is_complex:
                nested_lines = self._describe_schema_recursive(
                    field.nested_schema, label
                )
                lines.extend(nested_lines)

        return lines

    def _generate_instructions(self) -> str:
        # Root is always "1" based on your example
        structure_lines = self._describe_schema_recursive(self.schema, prefix="1")
        structure_block = "\n".join(structure_lines)

        return (
            f"\n{self._PROTOCOL_SIGNATURE}\n"
            f"[INSTRUCTIONS]\n"
            f"1. Interpret input strictly as a Recursive Compact Hierarchy.\n"
            f"2. Syntax: Complex objects enclosed in |{{ }}|, separated by comma.\n"
            f"3. Arrays marked with *, enclosed in [ ].\n"
            f"4. Structure Mapping:\n"
            f"# 1 = {self.schema.name} (Root)\n"
            f"{structure_block}\n"
            f"[END_PROTOCOL]\n"
        )

    def build(
        self, base_prompt: str, data: List[Any], data_marker: str = "[INPUT]"
    ) -> str:
        serialized = self.serializer.serialize(data)

        # Inject Data
        if data_marker in base_prompt:
            final_prompt = base_prompt.replace(data_marker, serialized)
        else:
            final_prompt = f"{base_prompt}\nDATA:\n{serialized}"

        # Inject Instructions
        if self._PROTOCOL_SIGNATURE not in final_prompt:
            final_prompt = f"{self._generate_instructions()}\n{final_prompt}"

        return final_prompt
