# 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 logging
import requests
from jingrow.model.page import Page
from jingrow.config import Config

logger = logging.getLogger(__name__)

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
        self.session_cookie = Config.jingrow_session_cookie
        logger.info(f"API adapter initialized with URL: {self.api_url}")
    
    def _get_headers(self):
        """获取请求头"""
        headers = {
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        }
        
        # 使用 Jingrow API 认证格式: token {api_key}:{api_secret}
        if self.api_key and self.api_secret:
            headers['Authorization'] = f'token {self.api_key}:{self.api_secret}'
        
        if self.session_cookie:
            headers['Cookie'] = f'sid={self.session_cookie}'
        
        return headers
    
    def _make_request(self, method: str, endpoint: str, data: Dict = None):
        """发送 API 请求"""
        url = f"{self.api_url}/{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:
            logger.error(f"API request failed: {e}")
            raise
    
    def _create_page(self, pagetype: str, name: str = None, **data):
        """创建 Page 对象的工厂方法"""
        page_data = {"pagetype": pagetype, **data}
        if name is not None:
            page_data["name"] = name
        return Page(page_data)
    
    def _build_endpoint(self, pagetype: str, name: str = None) -> str:
        """构建 API 端点"""
        endpoint = f"api/data/{pagetype}"
        if name:
            endpoint += f"/{name}"
        return endpoint
    
    def get_pg(self, *args, **kwargs):
        """获取页面类型文档 - 对齐云端 get_pg 接口
        
        支持多种调用方式：
        - get_pg("PageType", "name") - 获取指定文档
        - get_pg({"pagetype": "PageType", ...}) - 从字典创建文档  
        - get_pg(pagetype="PageType", field=...) - 关键字参数方式
        - get_pg("PageType", "name", for_update=True) - 带更新锁
        """
        pagetype = None
        name = None
        
        # 处理参数
        if args:
            if isinstance(args[0], str):
                pagetype = args[0]
                if len(args) > 1:
                    name = args[1]
            elif isinstance(args[0], dict):
                # 从字典创建文档
                kwargs = args[0]
            else:
                raise ValueError("First non keyword argument must be a string or dict")
        
        # 从 kwargs 中提取 pagetype
        if pagetype is None and kwargs:
            if "pagetype" in kwargs:
                pagetype = kwargs["pagetype"]
            else:
                raise ValueError('"pagetype" is a required key')
        
        logger.info(f"API get_pg: {pagetype}, {name}")
        
        # 如果只有 pagetype 没有 name，返回列表
        if name is None:
            # 从 kwargs 中移除 pagetype，避免参数冲突
            list_kwargs = kwargs.copy()
            list_kwargs.pop('pagetype', None)
            return self.get_list(pagetype, **list_kwargs)
        
        # 获取单个文档
        endpoint = self._build_endpoint(pagetype, name)
        data = self._make_request('GET', endpoint, kwargs)
        
        # 如果 API 返回的数据中有 name，先移除它，使用我们指定的 name
        if isinstance(data, dict) and 'name' in data:
            api_name = data.pop('name')
        
        return self._create_page(pagetype, name, **data)
    
    def get_list(self, pagetype: str, fields=None, filters=None, group_by=None, 
                 order_by=None, limit_start=None, limit_page_length=20, 
                 parent=None, debug=False, as_dict=True, or_filters=None, **kwargs):
        """获取页面类型列表 - 对齐云端 get_list 接口
        
        :param pagetype: PageType on which query is to be made.
        :param fields: List of fields or `*`.
        :param filters: List of filters (see example).
        :param order_by: Order By e.g. `modified desc`.
        :param limit_start: Start results at record #. Default 0.
        :param limit_page_length: No of records in the page. Default 20.
        :param group_by: Group by field.
        :param or_filters: OR filter conditions.
        :param debug: Debug mode.
        :param as_dict: Return as dict format.
        
        Example usage:
        - get_list("ToDo", fields=["name", "description"], filters={"owner":"test@example.com"})
        - get_list("ToDo", fields="*", filters=[["modified", ">", "2014-01-01"]])
        """
        logger.info(f"API get_list: {pagetype}")
        
        # 构建查询参数
        params = {}
        if fields is not None:
            params['fields'] = fields
        if filters is not None:
            params['filters'] = filters
        if group_by is not None:
            params['group_by'] = group_by
        if order_by is not None:
            params['order_by'] = order_by
        if limit_start is not None:
            params['limit_start'] = limit_start
        if limit_page_length != 20:  # 默认值不需要传递
            params['limit_page_length'] = limit_page_length
        if parent is not None:
            params['parent'] = parent
        if debug:
            params['debug'] = debug
        if not as_dict:  # 默认 True，只有 False 时才传递
            params['as_dict'] = as_dict
        if or_filters is not None:
            params['or_filters'] = or_filters
        
        # 合并其他参数
        params.update(kwargs)
        
        endpoint = self._build_endpoint(pagetype)
        data = self._make_request('GET', endpoint, params)
        
        return [self._create_page(pagetype, item.pop('name', None), **item) for item in data]
    
    def new_pg(self, pagetype: str, *, parent_pg=None, parentfield=None, as_dict=False, **kwargs):
        """创建新的页面类型文档 - 对齐云端 new_pg 接口
        
        :param pagetype: PageType of the new document.
        :param parent_pg: [optional] add to parent document.
        :param parentfield: [optional] add against this `parentfield`.
        :param as_dict: [optional] return as dictionary instead of Page.
        :param kwargs: [optional] You can specify fields as field=value pairs in function call.
        """
        logger.info(f"API new_pg: {pagetype}")
        
        # 构建新文档数据
        new_data = {
            "pagetype": pagetype,
            "__islocal": 1,
            "pagestatus": 0,
            **kwargs
        }
        
        # 如果有父文档，添加父文档信息
        if parent_pg:
            new_data["parent"] = parent_pg.name if hasattr(parent_pg, 'name') else str(parent_pg)
            new_data["parenttype"] = parent_pg.pagetype if hasattr(parent_pg, 'pagetype') else None
            if parentfield:
                new_data["parentfield"] = parentfield
        
        if as_dict:
            return new_data
        else:
            # 移除 pagetype 避免参数冲突
            pagetype_data = new_data.pop('pagetype')
            return self._create_page(pagetype_data, None, **new_data)
    
    def save_pg(self, pg, ignore_permissions=False, ignore_validate=False, ignore_mandatory=False):
        """保存页面类型文档 - 对齐云端 save_pg 接口
        
        :param pg: Page object to save
        :param ignore_permissions: Ignore permission checks
        :param ignore_validate: Ignore validation
        :param ignore_mandatory: Ignore mandatory field checks
        """
        logger.info(f"API save_pg: {pg.pagetype}, {getattr(pg, 'name', None)}")
        
        endpoint = self._build_endpoint(pg.pagetype, getattr(pg, 'name', None))
        method = 'PUT' if getattr(pg, 'name', None) else 'POST'
        data = pg.as_dict()
        
        # 添加保存选项
        if ignore_permissions:
            data['ignore_permissions'] = True
        if ignore_validate:
            data['ignore_validate'] = True
        if ignore_mandatory:
            data['ignore_mandatory'] = True
        
        result = self._make_request(method, endpoint, data)
        
        # 更新文档对象
        if result:
            # 直接更新对象的属性
            for key, value in result.items():
                setattr(pg, key, value)
        
        return pg
    
    def delete_pg(self, pagetype: str, name: str, ignore_missing=False):
        """删除页面类型文档 - 对齐云端 delete_pg 接口
        
        :param pagetype: PageType name
        :param name: Document name
        :param ignore_missing: Ignore if document doesn't exist
        """
        logger.info(f"API delete_pg: {pagetype}, {name}")
        
        endpoint = self._build_endpoint(pagetype, name)
        params = {'ignore_missing': ignore_missing} if ignore_missing else {}
        
        self._make_request('DELETE', endpoint, params)
        return True
    
    def db_exists(self, pagetype: str, filters: Dict[str, Any] = None, cache=False):
        """检查文档是否存在 - 对齐云端 db.exists 接口
        
        :param pagetype: PageType name
        :param filters: Filter conditions (dict or name string)
        :param cache: Enable caching for single document checks
        
        Examples:
        - db_exists("User", "jane@example.org", cache=True)
        - db_exists("User", {"full_name": "Jane Doe"})
        - db_exists({"pagetype": "User", "full_name": "Jane Doe"})
        """
        logger.info(f"API db_exists: {pagetype}, {filters}")
        
        # 处理字典格式的 pagetype
        if isinstance(pagetype, dict):
            filters = pagetype.copy()
            pagetype = filters.pop("pagetype")
        
        # 如果 filters 是字符串，转换为字典
        if isinstance(filters, str):
            filters = {"name": filters}
        
        endpoint = self._build_endpoint(pagetype)
        params = {'filters': filters} if filters else {}
        if cache:
            params['cache'] = cache
        
        data = self._make_request('GET', endpoint, params)
        return len(data) > 0
    
    def db_get_value(self, pagetype: str, filters: Dict[str, Any] = None, fieldname: str = None, 
                     ignore=False, cache=False, order_by=None, parent=None):
        """获取数据库值 - 对齐云端 db.get_value 接口
        
        :param pagetype: PageType name
        :param filters: Filter conditions (dict or name string)
        :param fieldname: Field name to get value for
        :param ignore: Ignore if document doesn't exist
        :param cache: Enable caching
        :param order_by: Order by field
        :param parent: Parent document for child table queries
        
        Examples:
        - db_get_value("User", "jane@example.org", "full_name")
        - db_get_value("User", {"email": "jane@example.org"}, "full_name")
        """
        logger.info(f"API db_get_value: {pagetype}, {filters}, {fieldname}")
        
        # 如果 filters 是字符串，转换为字典
        if isinstance(filters, str):
            filters = {"name": filters}
        
        endpoint = self._build_endpoint(pagetype)
        params = {
            'filters': filters,
            'fieldname': fieldname
        }
        if ignore:
            params['ignore'] = ignore
        if cache:
            params['cache'] = cache
        if order_by:
            params['order_by'] = order_by
        if parent:
            params['parent'] = parent
        
        data = self._make_request('GET', endpoint, params)
        return data
    
    def db_set_value(self, pagetype: str, filters: Dict[str, Any] = None, fieldname: str = None, 
                     value: Any = None, modified=None, modified_by=None, update_modified=True, debug=False):
        """设置数据库值 - 对齐云端 db.set_value 接口
        
        :param pagetype: PageType name
        :param filters: Filter conditions (dict or name string)
        :param fieldname: Field name to set value for
        :param value: Value to set
        :param modified: Use this as the modified timestamp
        :param modified_by: Set this user as modified_by
        :param update_modified: Update the modified timestamp
        :param debug: Debug mode
        
        Examples:
        - db_set_value("User", "jane@example.org", "full_name", "Jane Doe")
        - db_set_value("User", {"email": "jane@example.org"}, "full_name", "Jane Doe")
        """
        logger.info(f"API db_set_value: {pagetype}, {filters}, {fieldname}, {value}")
        
        # 如果 filters 是字符串，转换为字典
        if isinstance(filters, str):
            filters = {"name": filters}
        
        endpoint = self._build_endpoint(pagetype)
        data = {
            'filters': filters,
            'fieldname': fieldname,
            'value': value
        }
        if modified:
            data['modified'] = modified
        if modified_by:
            data['modified_by'] = modified_by
        if not update_modified:
            data['update_modified'] = update_modified
        if debug:
            data['debug'] = debug
        
        self._make_request('PUT', endpoint, data)
        return True
    
