"""
应用创建节点

创建一个新的应用（子应用）
"""
import logging
from typing import Any, Dict, Optional

from ..base import BaseNode, NodeContext, NodeResult
from ..registry import NodeRegistry

logger = logging.getLogger(__name__)


@NodeRegistry.register
class AppCreateNode(BaseNode):
    """
    应用创建节点

    创建一个新的应用（低代码平台的顶层容器）
    """

    node_type = 'app_create'
    node_name = '创建应用'
    node_category = 'application'
    node_icon = 'app-window'
    node_description = '创建一个新的应用（子应用）'

    inputs = [
        {
            'name': 'name',
            'type': 'string',
            'description': '应用名称',
            'required': True,
        },
        {
            'name': 'code',
            'type': 'string',
            'description': '应用编码（唯一标识，用于URL路由，只能包含字母、数字、下划线和连字符，必须以字母开头）',
            'required': True,
        },
        {
            'name': 'description',
            'type': 'string',
            'description': '应用描述',
            'required': False,
        },
        {
            'name': 'icon',
            'type': 'string',
            'description': '应用图标',
            'required': False,
        },
        {
            'name': 'app_type',
            'type': 'string',
            'description': '应用类型: form-表单应用, workflow-流程应用, dashboard-数据应用, screen-大屏应用, mixed-混合应用',
            'required': False,
        },
    ]

    outputs = [
        {
            'name': 'app_id',
            'type': 'string',
            'description': '创建的应用ID',
        },
        {
            'name': 'app_code',
            'type': 'string',
            'description': '应用编码',
        },
        {
            'name': 'app_name',
            'type': 'string',
            'description': '应用名称',
        },
        {
            'name': 'success',
            'type': 'boolean',
            'description': '是否创建成功',
        },
    ]

    def execute(self, context: NodeContext) -> NodeResult:
        """执行节点（同步方法，通过运行异步方法实现）"""
        import asyncio

        loop = asyncio.get_event_loop()
        if loop.is_running():
            import concurrent.futures
            with concurrent.futures.ThreadPoolExecutor() as executor:
                future = executor.submit(asyncio.run, self.execute_async(context))
                return future.result()
        else:
            return loop.run_until_complete(self.execute_async(context))

    async def execute_async(self, context: NodeContext) -> NodeResult:
        """异步执行节点"""
        try:
            # 获取输入参数并解析变量引用
            name = context.resolve_template(self.config.get('name', ''))
            code_base = context.resolve_template(self.config.get('code', ''))
            description = context.resolve_template(self.config.get('description', ''))
            icon = context.resolve_template(self.config.get('icon', ''))
            app_type = context.resolve_template(self.config.get('app_type', 'mixed'))

            # 配置选项
            update_if_exists = self.config.get('update_if_exists', False)

            logger.info(f'AppCreateNode - 开始创建应用: name={name}, code={code_base}')

            # 验证必要参数
            if not name:
                return NodeResult(
                    success=False,
                    error='应用名称不能为空',
                )

            if not code_base:
                return NodeResult(
                    success=False,
                    error='应用编码不能为空',
                )

            # 验证编码格式（字母开头，只能包含字母、数字、下划线和连字符）
            import re
            if not re.match(r'^[a-zA-Z][a-zA-Z0-9_-]*$', code_base):
                return NodeResult(
                    success=False,
                    error='应用编码格式不正确，必须以字母开头，只能包含字母、数字、下划线和连字符',
                )

            # 导入服务和数据库会话
            from app.database import AsyncSessionLocal
            from core.application.service import ApplicationService
            from core.application.schema import ApplicationCreate, ApplicationUpdate

            async with AsyncSessionLocal() as db:
                # 生成唯一的 code（如果已存在则自动添加后缀）
                code = await self._get_unique_code(db, code_base, ApplicationService)
                logger.info(f'AppCreateNode - 使用 code: {code} (原始: {code_base})')

                # 检查应用编码是否已存在（理论上不应该存在，因为已经生成了唯一 code）
                existing_app = await ApplicationService.get_by_code(db, code)

                if existing_app:
                    if update_if_exists:
                        # 更新已存在的应用
                        update_data = ApplicationUpdate(
                            name=name,
                            description=description or None,
                            icon=icon or None,
                            app_type=app_type or None,
                        )
                        updated_app = await ApplicationService.update(
                            db,
                            record_id=existing_app.id,
                            data=update_data,
                            auto_commit=True
                        )

                        if updated_app:
                            logger.info(f'AppCreateNode - 应用已存在，更新成功: id={updated_app.id}')
                            return NodeResult(
                                success=True,
                                output=f'应用 {name} 更新成功',
                                output_variables={
                                    'app_id': updated_app.id,
                                    'app_code': updated_app.code,
                                    'app_name': updated_app.name,
                                    'success': True,
                                }
                            )
                        else:
                            return NodeResult(
                                success=False,
                                error=f'更新应用失败',
                            )
                    else:
                        # 应用已存在，返回已存在的应用信息
                        logger.info(f'AppCreateNode - 应用编码已存在: code={code}, id={existing_app.id}')
                        return NodeResult(
                            success=True,
                            output=f'应用编码 {code} 已存在',
                            output_variables={
                                'app_id': existing_app.id,
                                'app_code': existing_app.code,
                                'app_name': existing_app.name,
                                'success': False,  # 标记为未创建新应用
                            }
                        )

                # 创建新应用
                create_data = ApplicationCreate(
                    name=name,
                    code=code,
                    description=description or '',
                    icon=icon or '',
                    app_type=app_type or 'mixed',
                )

                new_app = await ApplicationService.create(db, data=create_data, auto_commit=True)

                if new_app:
                    logger.info(f'AppCreateNode - 应用创建成功: id={new_app.id}, code={new_app.code}')
                    return NodeResult(
                        success=True,
                        output=f'应用 {name} 创建成功',
                        output_variables={
                            'app_id': new_app.id,
                            'app_code': new_app.code,
                            'app_name': new_app.name,
                            'success': True,
                        }
                    )
                else:
                    return NodeResult(
                        success=False,
                        error='创建应用失败',
                    )

        except Exception as e:
            logger.exception(f'AppCreateNode - 执行异常: {e}')
            return NodeResult(
                success=False,
                error=f'创建应用异常: {str(e)}',
            )

    async def _get_unique_code(self, db, base_code: str, service) -> str:
        """
        生成唯一的 code，如果已存在则自动添加数字后缀

        Args:
            db: 数据库会话
            base_code: 基础 code
            service: 服务类（需要有 get_by_code 方法）

        Returns:
            唯一的 code
        """
        code = base_code
        counter = 1

        while True:
            try:
                existing = await service.get_by_code(db, code)
                if not existing:
                    # code 不存在，可以使用
                    break
                # code 已存在，添加后缀
                code = f"{base_code}_{counter}"
                counter += 1
            except Exception:
                # 查询出错，认为 code 可用
                break

        return code
