#!/usr/bin/env python3
"""
PIVOT Executor
Company: eXonware.com
Author: eXonware Backend Team
Email: connect@exonware.com
Version: 0.0.1.8
"""

from typing import Any, Optional
from ..base import AUniversalOperationExecutor
from ....contracts import QueryAction, ExecutionContext, ExecutionResult
from ....defs import OperationType
from ..utils import extract_items, extract_field_value


class PivotExecutor(AUniversalOperationExecutor):
    """PIVOT - Pivot rows into columns."""
    OPERATION_NAME = "PIVOT"
    OPERATION_TYPE = OperationType.ADVANCED
    SUPPORTED_NODE_TYPES = []

    def _do_execute(self, action: QueryAction, context: ExecutionContext) -> ExecutionResult:
        params = action.params
        result_data = self._execute_pivot(context.node, params, context)
        return ExecutionResult(
            success=True,
            data=result_data,
            action_type=self.OPERATION_NAME,
            metadata={"operation": self.OPERATION_NAME},
        )

    def _aggregate(self, values: list[Any], agg: str) -> Any:
        if not values:
            return None
        if agg == "count":
            return len(values)
        if agg == "first":
            return values[0]
        numeric_values = [v for v in values if isinstance(v, (int, float))]
        if agg == "sum":
            return sum(numeric_values)
        if agg == "avg":
            return (sum(numeric_values) / len(numeric_values)) if numeric_values else None
        return values[0]

    def _execute_pivot(self, node: Any, params: dict, context: ExecutionContext) -> dict:
        items = extract_items(node)
        row_field = params.get("row_field")
        column_field = params.get("column_field")
        value_field = params.get("value_field")
        agg = str(params.get("agg", "sum")).lower()

        if not row_field or not column_field or not value_field:
            return {"items": [], "count": 0, "error": "row_field, column_field and value_field are required"}

        grouped: dict[Any, dict[Any, list[Any]]] = {}
        columns: set[Any] = set()

        for item in items:
            row_key = extract_field_value(item, row_field)
            col_key = extract_field_value(item, column_field)
            val = extract_field_value(item, value_field)
            columns.add(col_key)
            grouped.setdefault(row_key, {}).setdefault(col_key, []).append(val)

        pivoted = []
        for row_key, col_map in grouped.items():
            row_record = {row_field: row_key}
            for col in columns:
                row_record[str(col)] = self._aggregate(col_map.get(col, []), agg)
            pivoted.append(row_record)

        return {
            "items": pivoted,
            "count": len(pivoted),
            "columns": [str(c) for c in sorted(columns, key=lambda x: str(x))],
            "agg": agg,
        }
