"""BLCE DDL Executor — execute generated DDL on Snowflake.

Runs GeneratedDDL statements with timing, error isolation, and dry-run
support.  Dimensions are executed before facts so FK references resolve.
"""
from __future__ import annotations

import logging
import time
from datetime import datetime, timezone
from typing import Any, List

from .contracts import (
    DDLExecutionResult,
    DeploymentStatus,
    GeneratedDDL,
)

logger = logging.getLogger(__name__)


class DDLExecutor:
    """Execute GeneratedDDL statements on a Snowflake connection."""

    def execute_ddl(
        self,
        ddl: GeneratedDDL,
        connection: Any,
        dry_run: bool = False,
    ) -> DDLExecutionResult:
        """Execute a single DDL statement.

        Args:
            ddl: The GeneratedDDL to execute.
            connection: A Snowflake connection object with .cursor().
            dry_run: If True, return SKIPPED without executing.

        Returns:
            DDLExecutionResult with status, timing, and error info.
        """
        result = DDLExecutionResult(
            ddl_id=ddl.ddl_id,
            object_name=ddl.object_name,
            object_type=ddl.object_type,
            executed_sql=ddl.ddl_sql,
        )

        if dry_run:
            result.status = DeploymentStatus.SKIPPED
            return result

        result.status = DeploymentStatus.RUNNING
        start = time.perf_counter()
        try:
            cursor = connection.cursor()
            try:
                # Execute only the CREATE TABLE statement (first statement)
                cursor.execute(ddl.ddl_sql)
                result.rows_affected = cursor.rowcount or 0
                result.status = DeploymentStatus.SUCCESS
            finally:
                cursor.close()
        except Exception as exc:
            result.status = DeploymentStatus.FAILED
            result.error_message = str(exc)
            logger.warning("DDL execution failed for %s: %s", ddl.object_name, exc)
        finally:
            elapsed_ms = (time.perf_counter() - start) * 1000
            result.execution_time_ms = round(elapsed_ms, 2)
            result.executed_at = datetime.now(timezone.utc).isoformat()

        return result

    def execute_all(
        self,
        ddls: List[GeneratedDDL],
        connection: Any,
        dry_run: bool = False,
    ) -> List[DDLExecutionResult]:
        """Execute all DDLs — dimensions first, then facts.

        Args:
            ddls: List of GeneratedDDL objects.
            connection: Snowflake connection.
            dry_run: If True, skip execution.

        Returns:
            List of DDLExecutionResult in execution order.
        """
        # Sort: dimensions first (for FK dependency order)
        sorted_ddls = sorted(ddls, key=lambda d: 0 if d.object_type == "dimension" else 1)

        results: List[DDLExecutionResult] = []
        for ddl in sorted_ddls:
            result = self.execute_ddl(ddl, connection, dry_run=dry_run)
            results.append(result)

        return results

