# Copyright (c) 2025, JINGROW and contributors
# For license information, please see license.txt

"""
jlocal 相关白名单函数 - 转发到 SaaS 端
"""

import json
import logging
import os
import shutil
import tempfile
from pathlib import Path
from typing import Dict, Any

import requests
from fastapi import HTTPException

import jingrow
from jingrow.config import Config
from jingrow.utils.auth import get_request_session_cookie
from jingrow.utils.path import get_jingrow_root

logger = logging.getLogger(__name__)


@jingrow.whitelist()
def get_user_pagetype_permissions(**kwargs):
    """获取用户 PageType 权限 - 转发到 SaaS 端"""
    url = f"{Config.jingrow_server_url}/api/action/jingrow.ai.utils.jlocal.get_user_pagetype_permissions"
    headers = {"Accept": "application/json", "Content-Type": "application/json"}
    
    session_cookie = get_request_session_cookie()
    if session_cookie:
        headers["Cookie"] = f"sid={session_cookie}"
    
    resp = requests.post(url, headers=headers, json=kwargs, timeout=30)
    if resp.status_code == 200:
        return resp.json().get("message", {})
    logger.error(f"[get_user_pagetype_permissions] SaaS error: {resp.status_code} - {resp.text[:200]}")
    return {}

@jingrow.whitelist()
def get_all_node_metadata():
	"""
	获取所有节点的元数据，用于流程编排界面
	"""
	try:
		jingrow_root = get_jingrow_root()
		nodes_root = jingrow_root / "ai" / "nodes"
		
		if not nodes_root.exists():
			return {"success": True, "data": {}}
		
		metadata_map = {}
		
		for node_dir in nodes_root.iterdir():
			if not node_dir.is_dir():
				continue
			json_file = node_dir / f"{node_dir.name}.json"
			if not json_file.exists():
				continue
			
			try:
				with open(json_file, "r", encoding="utf-8") as f:
					data = json.load(f)
				
				metadata = data.get("metadata") or {}
				node_type = metadata.get("type")
				if not node_type:
					continue
				
				metadata_map[node_type] = {
					"type": node_type,
					"label": metadata.get("label") or node_type,
					"icon": metadata.get("icon") or "fa-cube",
					"color": metadata.get("color") or "#6b7280",
					"description": metadata.get("description") or "",
					"group": metadata.get("group") or "其他",
					"component_type": metadata.get("component_type") or "GenericNode"
				}
			except Exception:
				continue
		
		return {"success": True, "data": metadata_map}
		
	except Exception as e:
		return {"success": False, "error": str(e), "data": {}}


@jingrow.whitelist()
def get_node_schema(node_type: str = None):
	"""
	获取指定节点类型的Schema配置
	"""
	try:
		if not node_type:
			return {"success": False, "error": "node_type is required"}
		
		jingrow_root = get_jingrow_root()
		nodes_root = jingrow_root / "ai" / "nodes"
		json_file = nodes_root / node_type / f"{node_type}.json"
		
		if not json_file.exists():
			return {"success": False, "error": f"Node type {node_type} not found"}
		
		with open(json_file, "r", encoding="utf-8") as f:
			data = json.load(f)
		
		schema = dict(data)
		schema.pop("metadata", None)
		
		return {"success": True, "data": schema}
		
	except Exception as e:
		return {"success": False, "error": str(e)}


@jingrow.whitelist()
def get_node_schema_fields(node_type: str) -> Dict[str, Any]:
	"""获取指定节点类型的Schema字段列表"""
	if not node_type:
		return {"success": True, "fields": []}
	
	try:
		base_path = jingrow.get_app_path("jingrow")
		json_file = os.path.join(base_path, "ai", "nodes", node_type, f"{node_type}.json")
		
		if not os.path.exists(json_file):
			return {"success": True, "fields": []}
		
		with open(json_file, 'r', encoding='utf-8') as f:
			data = json.load(f)
		
		# 移除metadata获取schema
		schema = dict(data)
		schema.pop('metadata', None)
		
		# 提取字段列表
		fields = []
		if schema.get('properties'):
			for name, config in schema['properties'].items():
				fields.append({
					'name': name,
					'label': config.get('title', name),
					'type': config.get('type', 'string'),
					'description': config.get('description', '')
				})
		
		return {"success": True, "fields": fields}
		
	except FileNotFoundError:
		return {"success": True, "fields": []}
	except Exception as e:
		jingrow.log_error(f"获取节点字段失败: {node_type}", str(e))
		return {"success": True, "fields": []}


@jingrow.whitelist()
def import_local_nodes() -> Dict[str, Any]:
	"""一键导入本地节点到 Local Ai Node"""
	try:
		# 扫描本地节点目录
		jingrow_root = get_jingrow_root()
		nodes_path = jingrow_root / "ai" / "nodes"

		if not nodes_path.exists():
			return {
				"success": True,
				"matched": 0,
				"imported": 0,
				"skipped_existing": 0,
				"errors": []
			}

		matched = 0
		imported = 0
		skipped_existing = 0
		errors = []

		# 遍历节点目录
		for node_dir in nodes_path.iterdir():
			if not node_dir.is_dir():
				continue

			# 检查是否有对应的JSON配置文件
			json_file = node_dir / f"{node_dir.name}.json"
			if not json_file.exists():
				continue

			matched += 1

			try:
				# 读取节点配置
				with open(json_file, 'r', encoding='utf-8') as f:
					node_config = json.load(f)

				# 提取元数据
				metadata = node_config.get('metadata', {})
				node_type = metadata.get('type') or node_dir.name
				node_label = metadata.get('label', node_type)
				node_group = metadata.get('group', '')
				node_component = metadata.get('component_type', 'GenericNode')
				node_icon = metadata.get('icon', 'fa-cube')
				node_color = metadata.get('color', '#6b7280')
				node_description = metadata.get('description', '')

				# 检查节点是否已存在
				exists_res = jingrow.get_pg_id('Local Ai Node', field='node_type', value=node_type)
				if exists_res.get('success'):
					skipped_existing += 1
					continue

				# 生成 schema（移除 metadata）
				schema = dict(node_config)
				schema.pop('metadata', None)

				# 创建新节点
				result = jingrow.create_pg('Local Ai Node', {
					'node_type': node_type,
					'node_label': node_label,
					'node_group': node_group,
					'node_component': node_component,
					'node_icon': node_icon,
					'node_color': node_color,
					'node_description': node_description,
					'node_schema': schema,
					'status': 'Published'
				})

				if result:
					imported += 1
				else:
					errors.append(f"{node_type}: create failed")

			except Exception as e:
				error_msg = f"导入节点 {node_dir.name} 失败: {str(e)}"
				jingrow.log_error("导入本地节点失败", error_msg)
				errors.append(error_msg)

		return {
			"success": True,
			"matched": matched,
			"imported": imported,
			"skipped_existing": skipped_existing,
			"errors": errors
		}

	except Exception as e:
		jingrow.log_error("导入本地节点失败", str(e))
		return {
			"success": False,
			"error": str(e),
			"matched": 0,
			"imported": 0,
			"skipped_existing": 0
		}


@jingrow.whitelist()
def package_node(node_type: str) -> Dict[str, Any]:
	"""打包节点为zip文件"""
	if not node_type:
		jingrow.throw("参数错误", "node_type不能为空")
	
	try:
		import base64
		from datetime import datetime
		
		base_path = jingrow.get_app_path("jingrow")
		node_dir = os.path.join(base_path, "ai", "nodes", node_type)
		
		if not os.path.exists(node_dir):
			jingrow.throw("节点不存在", f"节点目录不存在: {node_type}")
		
		# 创建临时目录
		temp_dir = tempfile.mkdtemp()
		timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
		temp_package_dir = os.path.join(temp_dir, node_type)
		
		try:
			# 复制节点目录内容（排除不必要的文件）
			os.makedirs(temp_package_dir, exist_ok=True)
			for item in os.listdir(node_dir):
				if item in ['__pycache__', '.git', '.DS_Store', '.pytest_cache']:
					continue
				src = os.path.join(node_dir, item)
				dst = os.path.join(temp_package_dir, item)
				if os.path.isdir(src):
					shutil.copytree(src, dst)
				else:
					shutil.copy2(src, dst)
			
			# 打包为ZIP
			zip_filename = f"{node_type}-{timestamp}"
			zip_path = shutil.make_archive(
				os.path.join(temp_dir, zip_filename),
				'zip',
				root_dir=temp_dir,
				base_dir=node_type
			)
			
			# 读取文件内容
			with open(zip_path, 'rb') as f:
				zip_content = f.read()
			
			# 返回文件内容（base64编码）
			return {
				"success": True,
				"filename": f"{zip_filename}.zip",
				"content": base64.b64encode(zip_content).decode('utf-8')
			}
			
		finally:
			# 清理临时目录
			if os.path.exists(temp_dir):
				shutil.rmtree(temp_dir, ignore_errors=True)
			
	except Exception as e:
		jingrow.log_error(f"打包节点失败: {node_type}", str(e))
		jingrow.throw("打包失败", str(e))

