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

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


class TruncateExecutor(AUniversalOperationExecutor):
    """
    TRUNCATE operation executor - Universal operation.
    Removes all data/rows from a collection while preserving structure.
    Capability: Universal
    Operation Type: CORE
    """
    OPERATION_NAME = "TRUNCATE"
    OPERATION_TYPE = OperationType.CORE
    SUPPORTED_NODE_TYPES = []  # Universal

    def _do_execute(self, action: QueryAction, context: ExecutionContext) -> ExecutionResult:
        """Execute TRUNCATE operation."""
        params = action.params
        target = params.get('target')
        cascade = params.get('cascade', False)

        if not target:
            return ExecutionResult(
                success=False,
                data=None,
                error=f"TRUNCATE requires 'target'. Got: {action.params}",
                action_type=self.OPERATION_NAME
            )

        node = context.node
        result_data = self._execute_truncate(node, target, cascade, context)

        return ExecutionResult(
            success=True,
            data=result_data,
            action_type=self.OPERATION_NAME,
            metadata={
                'target': target,
                'cascade': cascade,
                'truncated_count': result_data.get('previous_count', 0)
            }
        )

    def _execute_truncate(self, node: Any, target: str, cascade: bool,
                          context: ExecutionContext) -> dict:
        """
        Actual TRUNCATE logic - removes all items from the target collection.
        Unlike DROP, TRUNCATE preserves the collection structure.
        O(1) for list.clear(), O(n) metadata snapshot.
        """
        try:
            # Resolve target collection
            collection = None
            if isinstance(node, dict) and target in node:
                collection = node[target]
            elif hasattr(node, 'get'):
                try:
                    collection = node.get(target, default=None)
                except Exception:
                    collection = None

            if collection is None:
                return {
                    'truncated': False,
                    'target': target,
                    'error': f"Collection '{target}' not found"
                }

            previous_items = extract_items(collection)
            previous_count = len(previous_items)

            # Clear the collection in place
            if isinstance(collection, list):
                collection.clear()
            elif isinstance(collection, dict):
                if cascade:
                    collection.clear()
                else:
                    keys = list(collection.keys())
                    for key in keys:
                        del collection[key]
            elif hasattr(collection, 'clear'):
                collection.clear()
            else:
                # For node-backed collections, attempt set to empty
                if isinstance(node, dict):
                    node[target] = type(collection)()
                elif hasattr(node, 'set'):
                    node.set(target, type(collection)())

            return {
                'truncated': True,
                'target': target,
                'previous_count': previous_count,
                'cascade': cascade
            }

        except Exception as e:
            return {
                'truncated': False,
                'target': target,
                'error': str(e)
            }


__all__ = ['TruncateExecutor']
