"""
Jingrow Local 应用安装 API
提供本地应用安装、管理等功能
"""

from fastapi import APIRouter, HTTPException, Request, UploadFile, File, Form
from typing import Dict, Any, List, Optional
import logging
import tempfile
import os
from pathlib import Path
import requests
import json
import shutil
import re

from jingrow.utils.app_installer import install_app, get_installed_apps as get_apps, get_app_directories
from jingrow.utils.jingrow_api import log_info, log_error
from jingrow.utils.auth import get_jingrow_cloud_url, get_jingrow_cloud_api_headers, get_jingrow_cloud_api_url, get_jingrow_api_headers
from jingrow.config import Config

logger = logging.getLogger(__name__)
router = APIRouter()


@router.post("/jingrow/install/upload")
async def install_app_from_upload(
    request: Request,
    file: UploadFile = File(...),
    app_name: Optional[str] = Form(None)
):

    try:
        log_info(f"开始处理上传的应用包: {file.filename}")
        
        # 验证文件类型
        if not file.filename.lower().endswith('.zip'):
            raise HTTPException(status_code=400, detail="只支持ZIP格式的安装包")
        
        # 保存上传文件到临时目录
        temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.zip')
        try:
            content = await file.read()
            temp_file.write(content)
            temp_file.close()
            
            # 安装应用
            result = install_app(temp_file.name, app_name)
            
            if result.get('success'):
                log_info(f"应用安装成功: {result.get('app_name')}")
                return result
            else:
                raise HTTPException(status_code=400, detail=result.get('error'))
                
        finally:
            # 清理临时文件
            try:
                os.unlink(temp_file.name)
            except:
                pass
                
    except HTTPException:
        raise
    except Exception as e:
        log_error(f"安装应用失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/jingrow/local-apps")
async def get_local_apps(request: Request):
    """扫描本地未安装的App"""
    try:
        current = Path(__file__).resolve()
        root = current.parents[4]
        apps_dir = root / "apps" 
        
        # 获取已安装的App列表 - 从Local Installed Apps PageType读取
        from jingrow import get_pg
        installed_names = set()
        try:
            # 使用正确的single PageType获取方式
            local_installed_apps = get_pg("Local Installed Apps", "Local Installed Apps")
            if local_installed_apps and hasattr(local_installed_apps, 'local_installed_apps') and local_installed_apps.local_installed_apps:
                installed_names = {app.app_name for app in local_installed_apps.local_installed_apps}
        except Exception:
            # 如果PageType不存在，使用文件系统扫描作为备选
            from jingrow.utils.app_installer import get_installed_apps as get_installed_apps_list
            installed_apps = get_installed_apps_list()
            installed_names = {app['name'] for app in installed_apps}
        
        # 系统默认App列表（需要排除）
        system_apps = {
            'jingrow', 'local_app_installer', 'local_jobs', 
            'local_apps', 'local_app', 'local_app_installer'
        }
        
        # 扫描apps目录
        local_apps = []
        if apps_dir.exists():
            for app_dir in apps_dir.iterdir():
                if (app_dir.is_dir() and 
                    app_dir.name not in installed_names and 
                    app_dir.name not in system_apps):
                    
                    # 检查是否有hooks.py文件
                    hooks_file = app_dir / app_dir.name / 'hooks.py'
                    
                    if hooks_file.exists():
                        try:
                            # 读取hooks.py获取App信息
                            with open(hooks_file, 'r', encoding='utf-8') as f:
                                content = f.read()
                                
                            app_info = {
                                'name': app_dir.name,
                                'path': str(app_dir),
                                'type': 'both' if (app_dir / "frontend").exists() else app_dir.name,
                                'title': app_dir.name.replace('_', ' ').title(),
                                'description': '',
                                'publisher': '',
                                'version': '1.0.0'
                            }
                            
                            # 提取App信息
                            import re
                            title_match = re.search(r'app_title\s*=\s*["\']([^"\']+)["\']', content)
                            if title_match:
                                app_info['title'] = title_match.group(1)
                                
                            desc_match = re.search(r'app_description\s*=\s*["\']([^"\']+)["\']', content)
                            if desc_match:
                                app_info['description'] = desc_match.group(1)
                                
                            pub_match = re.search(r'app_publisher\s*=\s*["\']([^"\']+)["\']', content)
                            if pub_match:
                                app_info['publisher'] = pub_match.group(1)
                            
                            local_apps.append(app_info)
                        except Exception as e:
                            # 如果读取失败，仍然添加基本信息
                            local_apps.append({
                                'name': app_dir.name,
                                'path': str(app_dir),
                                'type': app_dir.name,
                                'title': app_dir.name.replace('_', ' ').title(),
                                'description': '',
                                'publisher': '',
                                'version': '1.0.0'
                            })
        
        return {
            'success': True,
            'data': {
                'apps': local_apps,
                'total': len(local_apps)
            }
        }
        
    except Exception as e:
        log_error(f"扫描本地App失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.post("/jingrow/install-local/{app_name}")
async def install_local_app(request: Request, app_name: str):
    """安装本地App"""
    try:
        # 获取应用目录路径 - 修正路径
        current = Path(__file__).resolve()
        root = current.parents[4]  # 调整路径层级
        apps_dir = root / "apps"  # 新的apps目录
        app_dir = apps_dir / app_name
        
        if not app_dir.exists():
            raise HTTPException(status_code=404, detail=f"App '{app_name}' not found")
        
        # 检查是否已经安装 - 从Local Installed Apps PageType检查
        from jingrow import get_pg
        local_installed_apps = None
        try:
            # 使用正确的single PageType获取方式
            local_installed_apps = get_pg("Local Installed Apps", "Local Installed Apps")
            if local_installed_apps and hasattr(local_installed_apps, 'local_installed_apps') and local_installed_apps.local_installed_apps:
                for app in local_installed_apps.local_installed_apps:
                    if app.app_name == app_name:
                        raise HTTPException(status_code=400, detail=f"App '{app_name}' is already installed")
        except Exception:
            # 如果PageType不存在，跳过检查
            pass
        
        # 将App信息添加到Local Installed Apps PageType
        try:
            if not local_installed_apps:
                # 创建Local Installed Apps实例
                from jingrow import new_pg
                local_installed_apps = new_pg("Local Installed Apps")
            
            # 添加新的已安装App记录
            from jingrow import new_pg
            installed_app = new_pg("Installed Application")
            installed_app.app_name = app_name
            installed_app.app_version = "1.0.0"  # 可以从hooks.py读取版本
            installed_app.git_branch = "main"  # 默认分支
            
            # 添加到Local Installed Apps的表格字段
            if not hasattr(local_installed_apps, 'local_installed_apps') or not local_installed_apps.local_installed_apps:
                local_installed_apps.local_installed_apps = []
            local_installed_apps.local_installed_apps.append(installed_app)
            local_installed_apps.save()
        except Exception as e:
            # 如果PageType操作失败，记录日志但不阻止安装
            log_error(f"Failed to update Local Installed Apps PageType: {str(e)}")
        
        return {
            'success': True,
            'message': f"App '{app_name}' installed successfully",
            'app_name': app_name
        }
        
    except HTTPException:
        raise
    except Exception as e:
        log_error(f"安装本地App失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/jingrow/installed-apps")
async def get_installed_apps(request: Request):
    """获取已安装的应用列表 - 从Local Installed Apps PageType读取"""
    try:
        # 从Local Installed Apps PageType获取数据
        from jingrow import get_pg
        
        # 获取Local Installed Apps的single实例
        try:
            # 使用正确的single PageType获取方式
            local_installed_apps = get_pg("Local Installed Apps", "Local Installed Apps")
        except Exception as e:
            # 如果PageType不存在或为空，返回空列表
            return {
                'success': True,
                'data': {
                    'apps': [],
                    'total': 0
                }
            }
        
        apps = []
        if local_installed_apps and hasattr(local_installed_apps, 'local_installed_apps') and local_installed_apps.local_installed_apps:
            for app in local_installed_apps.local_installed_apps:
                apps.append({
                    'name': app.app_name,
                    'version': app.app_version,
                    'git_branch': app.git_branch,
                    'type': 'installed'
                })
        
        return {
            'success': True,
            'data': {
                'apps': apps,
                'total': len(apps)
            }
        }
        
    except Exception as e:
        log_error(f"获取已安装应用列表失败: {str(e)}")
        # 如果PageType相关操作失败，回退到文件系统扫描
        try:
            from jingrow.utils.app_installer import get_installed_apps as get_installed_apps_list
            installed_apps = get_installed_apps_list()
            apps = [{'name': app['name'], 'version': '1.0.0', 'git_branch': 'main', 'type': 'installed'} for app in installed_apps]
            return {
                'success': True,
                'data': {
                    'apps': apps,
                    'total': len(apps)
                }
            }
        except Exception as e2:
            raise HTTPException(status_code=500, detail=str(e2))


@router.post("/jingrow/uninstall/{app_name}")
async def uninstall_app(request: Request, app_name: str):

    try:
        log_info(f"开始卸载应用: {app_name}")
        
        # 检查应用是否存在
        backend_dir, frontend_dir = get_app_directories()
        backend_app_dir = backend_dir / app_name / app_name
        frontend_app_dir = frontend_dir / app_name / "frontend"
        
        if not backend_app_dir.exists() and not frontend_app_dir.exists():
            raise HTTPException(status_code=404, detail=f"应用 {app_name} 不存在")
        
        # 删除后端文件
        backend_result = {'success': True, 'message': '无后端文件'}
        if backend_app_dir.exists():
            try:
                shutil.rmtree(backend_app_dir)
                backend_result = {'success': True, 'message': '后端文件删除成功'}
                log_info(f"后端文件删除成功: {backend_app_dir}")
            except Exception as e:
                backend_result = {'success': False, 'error': f'后端文件删除失败: {str(e)}'}
        
        # 删除前端文件
        frontend_result = {'success': True, 'message': '无前端文件'}
        if frontend_app_dir.exists():
            try:
                shutil.rmtree(frontend_app_dir)
                frontend_result = {'success': True, 'message': '前端文件删除成功'}
                log_info(f"前端文件删除成功: {frontend_app_dir}")
            except Exception as e:
                frontend_result = {'success': False, 'error': f'前端文件删除失败: {str(e)}'}
        
        # 从数据库中删除记录
        db_result = await _remove_from_database(app_name)
        
        return {
            'success': True,
            'message': f'应用 {app_name} 卸载成功',
            'backend_result': backend_result,
            'frontend_result': frontend_result,
            'db_result': db_result
        }
        
    except HTTPException:
        raise
    except Exception as e:
        log_error(f"卸载应用 {app_name} 失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/jingrow/app-info/{app_name}")
async def get_app_info(request: Request, app_name: str):

    try:
        backend_dir, frontend_dir = get_app_directories()
        backend_app_dir = backend_dir / app_name / app_name
        frontend_app_dir = frontend_dir / app_name / "frontend"
        
        app_info = {
            'name': app_name,
            'has_backend': backend_app_dir.exists(),
            'has_frontend': frontend_app_dir.exists(),
            'backend_path': str(backend_app_dir) if backend_app_dir.exists() else None,
            'frontend_path': str(frontend_app_dir) if frontend_app_dir.exists() else None
        }
        
        # 尝试读取应用信息
        if backend_app_dir.exists():
            setup_py = backend_app_dir / 'setup.py'
            if setup_py.exists():
                try:
                    with open(setup_py, 'r', encoding='utf-8') as f:
                        content = f.read()
                        # 简单提取版本信息
                        version_match = re.search(r'version\s*=\s*["\']([^"\']+)["\']', content)
                        if version_match:
                            app_info['version'] = version_match.group(1)
                except:
                    pass
        
        if frontend_app_dir.exists():
            package_json = frontend_app_dir / 'package.json'
            if package_json.exists():
                try:
                    with open(package_json, 'r', encoding='utf-8') as f:
                        pkg_data = json.load(f)
                        app_info['version'] = pkg_data.get('version', app_info.get('version'))
                        app_info['description'] = pkg_data.get('description')
                except:
                    pass
        
        return {
            'success': True,
            'data': app_info
        }
        
    except Exception as e:
        log_error(f"获取应用信息失败: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


async def _remove_from_database(app_name: str) -> Dict[str, Any]:

    try:
        api_url = f"{Config.jingrow_server_url}/api/action/jingrow.core.pagetype.local_installed_apps.local_installed_apps.delete"
        
        headers = get_jingrow_api_headers()
        
        # 先查询记录
        query_url = f"{Config.jingrow_server_url}/api/action/jingrow.core.pagetype.local_installed_apps.local_installed_apps.get_list"
        query_payload = {
            'filters': {
                'app_name': app_name,
                'user_site': Config.jingrow_site or 'local'
            }
        }
        
        query_response = requests.post(query_url, json=query_payload, headers=headers, timeout=30)
        
        if query_response.status_code == 200:
            query_result = query_response.json()
            if isinstance(query_result, dict) and 'message' in query_result:
                query_result = query_result['message']
            
            if query_result.get('success') and query_result.get('data'):
                # 删除找到的记录
                for record in query_result['data']:
                    delete_payload = {'name': record['name']}
                    delete_response = requests.post(api_url, json=delete_payload, headers=headers, timeout=30)
                    
                    if delete_response.status_code == 200:
                        return {'success': True, 'message': '数据库记录删除成功'}
                    else:
                        return {'success': False, 'error': f'删除记录失败: HTTP {delete_response.status_code}'}
            else:
                return {'success': True, 'message': '未找到数据库记录'}
        else:
            return {'success': False, 'error': f'查询记录失败: HTTP {query_response.status_code}'}
            
    except Exception as e:
        return {'success': False, 'error': f'数据库操作异常: {str(e)}'}


@router.get("/jingrow/app-marketplace")
async def get_app_marketplace(
    search: Optional[str] = None,
    page: int = 1,
    page_size: int = 20,
    sort_by: Optional[str] = None
):
    """获取应用市场数据，支持搜索、分页和排序"""
    try:
        url = f"{get_jingrow_cloud_url()}/api/action/jcloud.api.local_app.get_local_apps"
        
        # 构建过滤条件
        filters = {"public": 1}
        if search:
            filters["title"] = ["like", f"%{search}%"]
        
        # 1. 先获取总数（不分页）
        total_params = {
            'filters': json.dumps(filters, ensure_ascii=False),
            'limit_start': 0,
            'limit_page_length': 0  # 不限制数量，获取所有数据来计算总数
        }
        
        headers = get_jingrow_cloud_api_headers()
        total_response = requests.get(url, params=total_params, headers=headers, timeout=20)
        
        total_count = 0
        if total_response.status_code == 200:
            total_data = total_response.json()
            total_count = len(total_data.get('message', []))
        
        # 2. 获取分页数据
        params = {
            'filters': json.dumps(filters, ensure_ascii=False)
        }
        
        # 排序参数
        if sort_by:
            params['order_by'] = sort_by
        
        # 分页参数
        limit_start = (page - 1) * page_size
        params['limit_start'] = limit_start
        params['limit_page_length'] = page_size
        
        response = requests.get(url, params=params, headers=headers, timeout=20)
        
        if response.status_code == 200:
            data = response.json()
            apps = data.get('message', [])
            
            # 返回分页格式的数据
            return {
                "items": apps,
                "total": total_count,
                "page": page,
                "page_size": page_size
            }
        else:
            raise HTTPException(status_code=response.status_code, detail="获取应用市场数据失败")
            
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取应用市场数据失败: {str(e)}")


@router.get("/jingrow/app-marketplace/{app_name}")
async def get_app_detail(app_name: str):
    """获取应用详情"""
    try:
        url = f"{get_jingrow_cloud_url()}/api/action/jcloud.api.local_app.get_local_app"
        params = {"name": app_name}
        
        headers = get_jingrow_cloud_api_headers()
        response = requests.get(url, params=params, headers=headers, timeout=20)
        
        if response.status_code == 200:
            data = response.json()
            return data.get('message')
        else:
            raise HTTPException(status_code=404, detail="应用不存在")
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取应用详情失败: {str(e)}")


@router.get("/jingrow/app-marketplace-meta")
async def get_app_meta():
    """获取Local App元数据"""
    try:
        url = f"{get_jingrow_cloud_url()}/api/action/jcloud.api.local_app.get_local_app_meta"
        
        headers = get_jingrow_cloud_api_headers()
        response = requests.get(url, headers=headers, timeout=20)
        
        if response.status_code == 200:
            data = response.json()
            return data.get('message')
        else:
            raise HTTPException(status_code=500, detail="获取元数据失败")
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取元数据失败: {str(e)}")


@router.post("/jingrow/upload-image")
async def upload_image(file: UploadFile = File(...)):
    """上传应用图片"""
    try:
        # 验证文件类型
        if not file.content_type or not file.content_type.startswith('image/'):
            raise HTTPException(status_code=400, detail="只支持图片格式")
        
        # 验证文件大小 (5MB限制)
        if file.size and file.size > 5 * 1024 * 1024:
            raise HTTPException(status_code=400, detail="图片大小不能超过5MB")
        
        # 读取文件内容
        file_content = await file.read()
        
        url = f"{get_jingrow_cloud_url()}/api/action/upload_file"
        headers = get_jingrow_cloud_api_headers()
        headers.pop('Content-Type', None)

        files = {'file': (file.filename, file_content, file.content_type)}
        data = {'file_name': file.filename, 'is_private': 0, 'folder': 'Home/Attachments'}
        
        response = requests.post(url, files=files, data=data, headers=headers, timeout=30)
        
        if response.status_code != 200:
            error_detail = response.json().get('detail', f"HTTP {response.status_code}") if response.headers.get('content-type', '').startswith('application/json') else f"HTTP {response.status_code}"
            raise HTTPException(status_code=response.status_code, detail=error_detail)
        
        result = response.json()
        
        # 检查错误
        if isinstance(result, dict) and result.get('error'):
            raise HTTPException(status_code=400, detail=result['error'])
        
        # 处理成功响应
        message = result.get('message', {})
        if isinstance(message, dict) and message.get('file_url'):
            file_url = message.get('file_url')
            # 确保URL格式正确
            if not file_url.startswith('/files/'):
                file_url = f"/files/{file_url.lstrip('/')}"
            
            return {
                "success": True,
                "url": file_url,
                "file_name": message.get('file_name'),
                "message": "图片上传成功"
            }
        
        raise HTTPException(status_code=400, detail="API响应格式错误")
        
    except HTTPException:
        raise
    except Exception as e:
        log_error(f"图片上传失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"图片上传失败: {str(e)}")



@router.post("/jingrow/create-app")
async def create_app(
    title: str = Form(...),
    app_name: str = Form(...),
    subtitle: str = Form(None),
    category: str = Form(None),
    description: str = Form(None),
    repository_url: str = Form(None),
    file_url: str = Form(None),
    app_image: str = Form(None)
):
    try:
        url = f"{get_jingrow_cloud_url()}/api/action/jcloud.api.local_app.create_local_app"
        
        headers = get_jingrow_cloud_api_headers()
        headers['Content-Type'] = 'application/json'
        
        response = requests.post(url, json={
            "app_data": {
                "app_name": app_name,
                "title": title,
                "subtitle": subtitle,
                "description": description,
                "category": category,
                "repository_url": repository_url,
                "file_url": file_url,
                "app_image": app_image
            }
        }, headers=headers, timeout=20)
        
        if response.status_code != 200:
            error_detail = response.json().get('detail', f"HTTP {response.status_code}") if response.headers.get('content-type', '').startswith('application/json') else f"HTTP {response.status_code}"
            raise HTTPException(status_code=response.status_code, detail=error_detail)
        
        result = response.json()
        
        # 检查错误
        if isinstance(result, dict) and result.get('error'):
            raise HTTPException(status_code=400, detail=result['error'])
        
        message = result.get('message', {})
        if isinstance(message, dict) and message.get('error'):
            raise HTTPException(status_code=400, detail=message['error'])
        
        # 成功响应
        app_name = message.get('name', 'unknown') if isinstance(message, dict) else result.get('message', 'unknown')
        return {"success": True, "message": f"应用发布成功，应用名称: {app_name}"}
        
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"发布失败: {str(e)}")

