"""DM Schema V1 → V2 Converter."""

from typing import Any

from .base import BaseDMConverter
from .types import AnnotationMeta, V2AnnotationData, V2ConversionResult


class DMV1ToV2Converter(BaseDMConverter):
    """Converter from DM Schema V1 to V2."""

    def _setup_tool_processors(self) -> None:
        """Register tool processors."""
        from .tools import (
            AnswerProcessor,
            BoundingBox3DProcessor,
            BoundingBoxProcessor,
            ClassificationProcessor,
            KeypointProcessor,
            NamedEntityProcessor,
            PolygonProcessor,
            PolylineProcessor,
            PromptProcessor,
            RelationProcessor,
            Segmentation3DProcessor,
            SegmentationProcessor,
        )

        self.register_processor(BoundingBoxProcessor())
        self.register_processor(PolygonProcessor())
        self.register_processor(PolylineProcessor())
        self.register_processor(KeypointProcessor())
        self.register_processor(BoundingBox3DProcessor())
        self.register_processor(SegmentationProcessor())
        self.register_processor(NamedEntityProcessor())
        self.register_processor(Segmentation3DProcessor())
        self.register_processor(ClassificationProcessor())
        self.register_processor(RelationProcessor())
        self.register_processor(PromptProcessor())
        self.register_processor(AnswerProcessor())

    def convert(self, v1_data: dict[str, Any]) -> V2ConversionResult:
        """Convert V1 data to V2 format (separated result)."""
        if 'annotations' not in v1_data:
            raise ValueError("V1 data requires 'annotations' field")
        if 'annotationsData' not in v1_data:
            raise ValueError("V1 data requires 'annotationsData' field")

        annotation_data = self._build_annotation_data(v1_data)
        annotation_meta = self._build_annotation_meta(v1_data)

        return {
            'annotation_data': annotation_data,
            'annotation_meta': annotation_meta,
        }

    def _build_annotation_data(self, v1_data: dict[str, Any]) -> V2AnnotationData:
        """Create annotation_data (V2 common structure) from V1 data."""
        annotations = v1_data.get('annotations', {})
        annotations_data = v1_data.get('annotationsData', {})

        classification_map = self._build_classification_map(annotations)

        result: V2AnnotationData = {
            'classification': classification_map,
        }

        for media_id, ann_list in annotations.items():
            singular_type, plural_type = self._extract_media_type_info(media_id)

            if plural_type not in result:
                result[plural_type] = []

            media_item = self._convert_media_item(media_id, ann_list, annotations_data.get(media_id, []))
            result[plural_type].append(media_item)

        return result

    def _build_annotation_meta(self, v1_data: dict[str, Any]) -> AnnotationMeta:
        """Create annotation_meta (V1 top-level structure) from V1 data."""
        return {
            'extra': v1_data.get('extra', {}),
            'annotations': v1_data.get('annotations', {}),
            'annotationsData': v1_data.get('annotationsData', {}),
            'relations': v1_data.get('relations', {}),
            'annotationGroups': v1_data.get('annotationGroups', {}),
            'assignmentId': v1_data.get('assignmentId'),
        }

    def _build_classification_map(self, annotations: dict[str, list[dict[str, Any]]]) -> dict[str, list[str]]:
        """Build classification map from annotations."""
        classification_map: dict[str, set[str]] = {}

        for media_id, ann_list in annotations.items():
            for ann in ann_list:
                tool = ann.get('tool', '')
                classification_obj = ann.get('classification') or {}
                class_label = classification_obj.get('class', '')

                if tool and class_label:
                    if tool not in classification_map:
                        classification_map[tool] = set()
                    classification_map[tool].add(class_label)

        return {tool: sorted(list(labels)) for tool, labels in classification_map.items()}

    def _convert_media_item(
        self,
        media_id: str,
        annotations: list[dict[str, Any]],
        annotations_data: list[dict[str, Any]],
    ) -> dict[str, list[dict[str, Any]]]:
        """Convert annotations for a single media item."""
        data_by_id = {item['id']: item for item in annotations_data if 'id' in item}

        result: dict[str, list[dict[str, Any]]] = {}

        for ann in annotations:
            ann_id = ann.get('id', '')
            tool = ann.get('tool', '')

            if not tool:
                continue

            processor = self.get_processor(tool)
            if not processor:
                supported_tools = list(self._tool_processors.keys())
                raise ValueError(f"Unsupported tool: '{tool}'. Supported tools: {', '.join(sorted(supported_tools))}")

            ann_data = data_by_id.get(ann_id, {})
            v2_annotation = processor.to_v2(ann, ann_data)

            if tool not in result:
                result[tool] = []
            result[tool].append(v2_annotation)

        return result
