"""Build node - executes Makefile-based build."""

import subprocess
from pathlib import Path
from typing import Any

from ..config import ConfigError, load_project_config
from ..logging_config import (
    get_logger,
    log_node_error,
    log_node_input_state,
    log_node_output_state,
    log_node_start,
    log_node_success,
)
from ..state import FirmwareState

logger = get_logger(__name__)


def build_node(state: FirmwareState) -> dict[str, Any]:
    """
    Build firmware using Makefile.

    Process:
    1. Validate project initialization
    2. Load project configuration
    3. Execute make build
    4. Update state with results
    """
    log_node_input_state("build", state)
    log_node_start("build", "build")

    # 1. Validate project initialization
    if not state.get("project_initialized"):
        error_msg = "Project not initialized. Run init first."
        log_node_error("build", error_msg)
        return {
            **state,
            "build_status": "error",
            "build_error_type": "config",
            "build_errors": [error_msg],
            "build_log": f"❌ {error_msg}",
        }

    project_root = state.get("project_root")
    if not project_root:
        error_msg = "Project root not set"
        log_node_error("build", error_msg)
        return {
            **state,
            "build_status": "error",
            "build_error_type": "config",
            "build_errors": [error_msg],
            "build_log": f"❌ {error_msg}",
        }

    # 2. Load project configuration
    try:
        project_root_path = Path(project_root)
        config = load_project_config(project_root_path)
        logger.info("🔨 Building project...")
    except ConfigError as e:
        error_msg = f"Config error: {str(e)}"
        log_node_error("build", error_msg)
        return {
            **state,
            "build_status": "error",
            "build_error_type": "config",
            "build_errors": [error_msg],
            "build_log": f"❌ {error_msg}",
        }

    # 3. Execute build using delegation script
    try:
        build_type = config.build_type  # "makefile" or "command"
        logger.info(f"🔧 Build type: {build_type}")

        # 動態載入並執行 delegation script
        import importlib
        import io
        import os
        import sys

        script_module = f"fwauto.scripts.build.{build_type}"

        try:
            module = importlib.import_module(script_module)
        except ImportError:
            error_msg = f"Unknown build type: {build_type}"
            log_node_error("build", error_msg)
            return {
                **state,
                "build_status": "error",
                "build_error_type": "config",
                "build_errors": [error_msg],
                "build_log": f"❌ {error_msg}",
            }

        # 切換到專案目錄並執行
        original_cwd = os.getcwd()
        os.chdir(project_root_path)

        try:
            # 使用 TeeIO 同時捕捉輸出並即時顯示到 console
            class TeeIO(io.StringIO):
                def __init__(self, original):
                    super().__init__()
                    self.original = original

                def write(self, s):
                    self.original.write(s)
                    self.original.flush()
                    return super().write(s)

            stdout_tee = TeeIO(sys.stdout)
            stderr_tee = TeeIO(sys.stderr)

            old_stdout, old_stderr = sys.stdout, sys.stderr
            sys.stdout, sys.stderr = stdout_tee, stderr_tee

            try:
                returncode = module.main()
            finally:
                sys.stdout, sys.stderr = old_stdout, old_stderr

            full_output = stdout_tee.getvalue() + stderr_tee.getvalue()
        finally:
            os.chdir(original_cwd)

        # Check success
        if returncode == 0:
            success_msg = "Build succeeded"
            log_node_success("build", success_msg)

            result_state = {
                **state,
                "build_status": "success",
                "build_error_type": None,
                "build_errors": [],
                "build_log": f"{full_output}\n✅ {success_msg}",
            }

            log_node_output_state("build", result_state)
            return result_state
        else:
            error_msg = f"Build failed with exit code {returncode}"
            log_node_error("build", error_msg)

            # 判斷錯誤類型：配置錯誤 vs 編譯錯誤
            # 配置錯誤關鍵字（delegation script 輸出）
            config_error_keywords = [
                "Config not found",
                "Makefile not found",
                "not configured",
                "command not configured",
            ]
            is_config_error = any(kw in full_output for kw in config_error_keywords)

            return {
                **state,
                "build_status": "error",
                "build_error_type": "config" if is_config_error else "build",
                "build_errors": [error_msg],
                "build_log": f"{full_output}\n❌ {error_msg}",
                "iteration": state.get("iteration", 0) + 1,
            }

    except subprocess.TimeoutExpired as e:
        error_msg = f"Build timeout after {e.timeout} seconds"
        log_node_error("build", error_msg)
        output = e.output if e.output else "No output captured"
        return {
            **state,
            "build_status": "error",
            "build_error_type": "build",  # timeout 是編譯錯誤，可以讓 AI 分析
            "build_errors": [error_msg],
            "build_log": f"{output}\n❌ {error_msg}",
            "iteration": state.get("iteration", 0) + 1,
        }
    except Exception as e:
        error_msg = f"Build exception: {str(e)}"
        log_node_error("build", error_msg)
        return {
            **state,
            "build_status": "error",
            "build_error_type": "config",  # 未知異常當作配置錯誤，不進 AI
            "build_errors": [error_msg],
            "build_log": f"❌ {error_msg}",
            "iteration": state.get("iteration", 0) + 1,
        }
