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

"""
Jingrow API 适配器, 通过 API 调用 Jingrow SaaS 版的服务
"""

from typing import Dict, List, Any, Optional, Union
import json
import os
import datetime
import requests
import pytz
from jingrow.config import Config
from jingrow.utils.auth import get_request_session_cookie

class ApiAdapter:
    """API 适配器 - 通过 API 调用 Jingrow SaaS 版"""
    
    def __init__(self, **config):
        self.api_url = Config.jingrow_server_url
        self.api_key = Config.jingrow_api_key
        self.api_secret = Config.jingrow_api_secret
    
    def _get_headers(self):
        """
        获取请求头
        
        认证优先级：
        1. 优先使用 ContextVar（由 SessionMiddleware 设置）
        2. 如果没有 session cookie，使用 API Key（系统级权限）
        """
        headers = {
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        }
        
        # 从 ContextVar 获取 session cookie
        session_cookie = get_request_session_cookie()
        
        # 优先使用 session cookie（用户权限）
        if session_cookie:
            headers['Cookie'] = f'sid={session_cookie}'
        # 如果没有 session cookie，使用 API Key（系统级权限）
        elif self.api_key and self.api_secret:
            headers['Authorization'] = f'token {self.api_key}:{self.api_secret}'
        
        return headers
    
    def _make_request(self, method: str, endpoint: str, data: Dict = None):
        """发送 API 请求"""
        # 允许传入完整 URL；否则按相对路径拼接
        url = endpoint if str(endpoint).startswith("http") else f"{self.api_url}/{str(endpoint).lstrip('/')}"
        headers = self._get_headers()
        
        try:
            if method.upper() == 'GET':
                response = requests.get(url, headers=headers, params=data)
            elif method.upper() == 'POST':
                response = requests.post(url, headers=headers, json=data)
            elif method.upper() == 'PUT':
                response = requests.put(url, headers=headers, json=data)
            elif method.upper() == 'DELETE':
                response = requests.delete(url, headers=headers)
            else:
                raise ValueError(f"Unsupported HTTP method: {method}")
            
            response.raise_for_status()
            return response.json()
        
        except requests.exceptions.RequestException as e:
            raise
    
    def get_logged_user(self, session_cookie: Optional[str] = None) -> Optional[str]:
        try:
            api_url = f"{self.api_url}/api/action/jingrow.auth.get_logged_user"
            if not session_cookie:
                return None
            headers = {
                "Content-Type": "application/json",
                "Accept": "application/json",
                "Cookie": f"sid={session_cookie}"
            }
            resp = requests.get(api_url, headers=headers, timeout=8)
            if resp.status_code == 200:
                data = resp.json()
                if isinstance(data, dict) and 'message' in data:
                    return data['message']
                return data
            return None
        except Exception:
            return None


    def get_field_mapping_from_jingrow(self, pagetype: str) -> Dict[str, str]:
        try:
            api_url = f"{self.api_url}/api/action/jingrow.ai.utils.jlocal.get_field_mapping"
            headers = self._get_headers()
            data = {'pagetype': pagetype}
            response = requests.post(api_url, json=data, headers=headers, timeout=10)
            if response.status_code == 200:
                result = response.json()
                if 'message' in result:
                    result = result['message']
                if result.get('success'):
                    return result.get('field_mapping', {})
                else:
                    return {}
            else:
                return {}
        except Exception as e:
            return {}

    def get_field_value_from_jingrow(self, pagetype: str, name: str, fieldname: str) -> Optional[Any]:
        try:
            api_url = f"{self.api_url}/api/action/jingrow.ai.utils.jlocal.get_field_value"
            headers = self._get_headers()
            data = { 'pagetype': pagetype, 'name': name, 'fieldname': fieldname }
            response = requests.post(api_url, json=data, headers=headers, timeout=10)
            if response.status_code == 200:
                result = response.json()
                if 'message' in result:
                    result = result['message']
                if result.get('success'):
                    return result.get('value')
                else:
                    return None
            else:
                return None
        except Exception as e:
            return None

    def get_ai_settings_from_jingrow(self) -> Optional[Dict[str, Any]]:
        try:
            api_url = f"{self.api_url}/api/action/jingrow.ai.utils.jlocal.get_ai_settings"
            headers = self._get_headers()
            response = requests.post(api_url, headers=headers, timeout=10)
            if response.status_code == 200:
                result = response.json()
                if result.get('session_expired'):
                    return None
                if 'message' in result:
                    result = result['message']
                if result.get('success'):
                    return result.get('config', {})
                else:
                    return None
            else:
                return None
        except Exception as e:
            return None

    def get_agent_detail(self, name: str) -> Optional[Dict[str, Any]]:
        try:
            api_url = f"{self.api_url}/api/action/jingrow.ai.utils.jlocal.get_local_ai_agent_detail"
            headers = self._get_headers()
            payload = {"name": name}
            response = requests.post(api_url, headers=headers, json=payload, timeout=15)
            if response.status_code == 200:
                data = response.json()
                if isinstance(data, dict) and 'message' in data:
                    message = data['message']
                    if isinstance(message, dict) and message.get('success'):
                        return message.get('data')
                return data
            else:
                return None
        except Exception as e:
            return None

    def get_pg(self, pagetype: str, name: str) -> Dict[str, Any]:
        try:
            api_url = f"{self.api_url}/api/data/{pagetype}/{name}"
            
            # PageType 元数据是公开的，所有用户都应该能读取
            # 强制使用管理员 API Key 获取 PageType 元数据
            if pagetype == 'PageType':
                headers = {
                    'Content-Type': 'application/json',
                    'Accept': 'application/json'
                }
                if self.api_key and self.api_secret:
                    headers['Authorization'] = f'token {self.api_key}:{self.api_secret}'
            else:
                headers = self._get_headers()
            
            response = requests.get(api_url, headers=headers, timeout=15)
            if response.status_code == 200:
                data = response.json()
                if isinstance(data, dict) and 'data' in data:
                    return {'success': True, 'data': data['data']}
                return {'success': True, 'data': data}
            else:
                return {'success': False, 'error': f"HTTP {response.status_code}: {response.text}"}
        except Exception as e:
            return {'success': False, 'error': f"获取记录异常: {str(e)}"}

    def create_pg(self, pagetype: str, payload: Dict[str, Any]) -> Dict[str, Any]:
        try:
            api_url = f"{self.api_url}/api/data/{pagetype}"
            headers = self._get_headers()
            response = requests.post(api_url, json=payload, headers=headers, timeout=20)
            if response.status_code in (200, 201):
                data = response.json()
                if isinstance(data, dict) and 'data' in data:
                    return {'success': True, 'data': data['data']}
                return {'success': True, 'data': data}
            else:
                return {'success': False, 'error': f"HTTP {response.status_code}: {response.text}"}
        except Exception as e:
            return {'success': False, 'error': f"创建记录异常: {str(e)}"}

    def update_pg(self, pagetype: str, name: str, payload: Dict[str, Any]) -> Dict[str, Any]:
        try:
            api_url = f"{self.api_url}/api/data/{pagetype}/{name}"
            headers = self._get_headers()
            response = requests.put(api_url, json=payload, headers=headers, timeout=20)
            if response.status_code in (200, 202):
                data = response.json()
                if isinstance(data, dict) and 'data' in data:
                    return {'success': True, 'data': data['data']}
                return {'success': True, 'data': data}
            else:
                return {'success': False, 'error': f"HTTP {response.status_code}: {response.text}"}
        except Exception as e:
            return {'success': False, 'error': f"更新记录异常: {str(e)}"}

    def update_local_job(self, data: Dict[str, Any]) -> Dict[str, Any]:
        return self.push_local_job_to_jingrow(data)

    def push_local_job_to_jingrow(self, data: Dict[str, Any]) -> Dict[str, Any]:
        try:
            api_url = f"{self.api_url}/api/action/jingrow.core.pagetype.local_job.local_job.push_local_job"
            headers = self._get_headers()
            headers.setdefault("X-Requested-With", "XMLHttpRequest")
            site_name = getattr(Config, "JINGROW_SITE", None) or os.getenv("JINGROW_SITE")
            if site_name:
                headers["X-Frappe-Site-Name"] = site_name
            resp = requests.post(api_url, json=data, headers=headers, timeout=10)
            if resp.status_code == 200:
                body = resp.json()
                if isinstance(body, dict) and 'message' in body:
                    body = body['message']
                if isinstance(body, dict) and body.get('success'):
                    return {'success': True}
                return {'success': False, 'error': str(body)}
            return {'success': False, 'error': f"HTTP {resp.status_code}: {resp.text}"}
        except Exception as e:
            return {'success': False, 'error': f"推送 Local Job 失败: {str(e)}"}

    def delete_pg(self, pagetype: str, name: str) -> Dict[str, Any]:
        try:
            api_url = f"{self.api_url}/api/data/{pagetype}/{name}"
            headers = self._get_headers()
            response = requests.delete(api_url, headers=headers, timeout=15)
            if response.status_code in (200, 202):
                return {'success': True}
            else:
                return {'success': False, 'error': f"HTTP {response.status_code}: {response.text}"}
        except Exception as e:
            return {'success': False, 'error': f"删除记录异常: {str(e)}"}


    def get_pg_list(self, pagetype: str, filters: Optional[List[List[Any]]] = None,
                         fields: Optional[List[str]] = None, limit: Optional[int] = None) -> Dict[str, Any]:
        try:
            base_url = f"{self.api_url}/api/data/{pagetype}"
            params: Dict[str, str] = {}
            if filters:
                params['filters'] = json.dumps(filters, ensure_ascii=False)
            if fields:
                params['fields'] = json.dumps(fields, ensure_ascii=False)
            if isinstance(limit, int) and limit > 0:
                params['limit'] = str(limit)
            
            # PageType 列表也应该使用 API Key 获取
            if pagetype == 'PageType':
                headers = {
                    'Content-Type': 'application/json',
                    'Accept': 'application/json'
                }
                if self.api_key and self.api_secret:
                    headers['Authorization'] = f'token {self.api_key}:{self.api_secret}'
            else:
                headers = self._get_headers()
            
            response = requests.get(base_url, params=params, headers=headers, timeout=20)
            if response.status_code == 200:
                data = response.json()
                if isinstance(data, dict) and 'data' in data:
                    return {'success': True, 'data': data['data']}
                if isinstance(data, list):
                    return {'success': True, 'data': data}
                return {'success': True, 'data': [data]}
            else:
                return {'success': False, 'error': f"HTTP {response.status_code}: {response.text}"}
        except Exception as e:
            return {'success': False, 'error': f"列表查询异常: {str(e)}"}

    def get_page_meta(self, pagetype: str) -> Dict[str, Any]:
        try:
            api_url = f"{self.api_url}/api/action/jingrow.ai.utils.jlocal.get_meta"
            headers = self._get_headers()
            payload = {"pagetype": pagetype}
            response = requests.post(api_url, json=payload, headers=headers, timeout=10)
            if response.status_code == 200:
                result = response.json()
                if isinstance(result, dict) and 'message' in result:
                    result = result['message']
                if isinstance(result, dict) and result.get('success'):
                    return {'success': True, 'data': result.get('data', {})}
                return {'success': False, 'error': result.get('error', '获取Meta失败') if isinstance(result, dict) else '获取Meta失败'}
            else:
                return {'success': False, 'error': f"HTTP {response.status_code}: {response.text}"}
        except Exception as e:
            return {'success': False, 'error': f"获取Meta异常: {str(e)}"}

    def get_pagetype_module_app(self, pagetype: str) -> Dict[str, Any]:
        try:
            api_url = f"{self.api_url}/api/action/jingrow.ai.utils.jlocal.get_pagetype_module_app"
            headers = self._get_headers()
            payload = {"pagetype": pagetype}
            response = requests.post(api_url, json=payload, headers=headers, timeout=10)
            if response.status_code == 200:
                data = response.json()
                if isinstance(data, dict) and 'message' in data:
                    data = data['message']
                if isinstance(data, dict) and data.get('success'):
                    module_val = data.get('module') or (data.get('data') or {}).get('module')
                    app_val = data.get('app') or (data.get('data') or {}).get('app')
                    return {'success': True, 'module': module_val, 'app': app_val}
                return {'success': False, 'error': data.get('error', '获取失败') if isinstance(data, dict) else '获取失败'}
            return {'success': False, 'error': f"HTTP {response.status_code}: {response.text}"}
        except Exception as e:
            return {'success': False, 'error': f"获取模块信息异常: {str(e)}"}

    def get_pg_id(self, pagetype: str, filters: Optional[List[List[Any]]] = None,
                       field: Optional[str] = None, value: Optional[str] = None,
                       site: Optional[str] = None) -> Dict[str, Any]:
        try:
            query_filters: List[List[Any]] = []
            if isinstance(filters, list) and filters:
                query_filters = filters
            elif field and (value is not None):
                query_filters = [[field, '=', value]]
            if site:
                query_filters.append(['site', '=', site])

            res = self.get_pg_list(pagetype, filters=query_filters, fields=['name'], limit=1)
            if not res.get('success'):
                return {'success': False, 'error': res.get('error', '查询失败')}
            data = res.get('data') or []
            if not data:
                return {'success': False, 'error': '未找到记录'}
            name_val = (data[0] or {}).get('name')
            if not name_val:
                return {'success': False, 'error': '记录缺少name字段'}
            return {'success': True, 'name': name_val}
        except Exception as e:
            return {'success': False, 'error': f'获取记录name失败: {str(e)}'}

    def get_jingrow_system_timezone(self):
        try:
            headers = self._get_headers()
            url = f"{self.api_url}/api/action/jingrow.core.pagetype.system_settings.system_settings.load"
            response = requests.post(url, headers=headers, timeout=5)
            if response.status_code == 200:
                timezone_name = response.json().get('message', {}).get('defaults', {}).get('time_zone')
                if timezone_name:
                    return pytz.timezone(timezone_name)
        except (requests.RequestException, pytz.exceptions.UnknownTimeZoneError, KeyError):
            pass
        return self._get_default_timezone()

    def _get_default_timezone(self):
        return datetime.datetime.now().astimezone().tzinfo

    
