"""
可复用的JSON表格组件
封装了StreamLit AgGrid表格的JSON列显示和交互功能
"""

import json
import pandas as pd
import streamlit as st
import numpy as np
from pathlib import Path
from st_aggrid import AgGrid, AgGridReturn, GridOptionsBuilder, DataReturnMode, GridUpdateMode
from .cell_viewer import CellViewer
from .json_path_extractor import JsonPathExtractor
from super_datascope.common.lang_util import is_not_empty
from super_datascope.common.json_util import extract_json_by_path
from super_datascope.common.code_formatter import CodeFormatter
from super_datascope import logger

class JsonFormatter:
    """JSON列格式化工具类"""
    
    @staticmethod
    def format_json_column(value, display_mode="json"):
        """格式化JSON列的显示"""
        if value is None:
            return ""
        
        if isinstance(value, str) and value == "":
            return ""
        
        # 对于numpy数组，使用特殊处理
        if isinstance(value, np.ndarray):
            if value.size == 0:
                return ""
        else:
            # 对于非数组类型，使用pandas的isna检查
            try:
                if pd.isna(value):
                    return ""
            except (ValueError, TypeError):
                pass
        
        try:
            # 如果是字符串，尝试解析JSON
            if isinstance(value, str):
                data = json.loads(value)
            elif isinstance(value, np.ndarray):
                # 将numpy数组转换为Python列表以便JSON序列化
                data = value.tolist()
            else:
                data = value
                
            if display_mode == "chat_list":
                return JsonFormatter.format_chat_list(data)
            else:
                try:
                    json_str = json.dumps(data, ensure_ascii=False, indent=2)
                    return json_str[:200] + "..." if len(json_str) > 200 else json_str
                except (TypeError, ValueError):
                    # 如果无法JSON序列化，转为字符串
                    str_repr = str(data)
                    return str_repr[:200] + "..." if len(str_repr) > 200 else str_repr
        except:
            str_repr = str(value)
            return str_repr[:200] + "..." if len(str_repr) > 200 else str_repr

    @staticmethod
    def format_chat_list(messages_data):
        """将messages数据格式化为聊天列表显示"""
        try:
            if not isinstance(messages_data, list):
                return str(messages_data)
            
            chat_lines = []
            for msg in messages_data[:5]:  # 只显示前5条消息
                if isinstance(msg, dict):
                    role = msg.get('role', 'unknown')
                    content = msg.get('content', msg.get('message', ''))
                    chat_lines.append(f"{role}: {content[:50]}{'...' if len(str(content)) > 50 else ''}")
                else:
                    chat_lines.append(str(msg)[:50])
            
            if len(messages_data) > 5:
                chat_lines.append(f"... 还有{len(messages_data) - 5}条消息")
                
            return "\n".join(chat_lines)
        except:
            return str(messages_data)[:200]


class DataProcessor:
    """数据处理工具类"""
    
    @staticmethod
    def sort_columns_by_whitelist(df, whitelist):
        """根据白名单对DataFrame的列进行排序"""
        if not whitelist:
            return df
        
        # 获取所有列名
        all_columns = list(df.columns)
        
        # 白名单中存在于DataFrame中的列，按白名单顺序排列
        whitelist_columns = [col for col in whitelist if col in all_columns]
        
        # 不在白名单中的列，保持原有顺序
        other_columns = [col for col in all_columns if col not in whitelist]
        
        # 重新排列列的顺序
        sorted_columns = whitelist_columns + other_columns
        
        return df[sorted_columns]

    @staticmethod
    def prepare_display_dataframe(df, config):
        """准备用于显示的DataFrame，格式化JSON列"""
        display_df = df.copy()
        
        if 'json_columns' not in config:
            return display_df
        
        json_columns = config['json_columns']
        
        for col_name, col_config in json_columns.items():
            if col_name in display_df.columns:
                default_mode = col_config.get('default_mode', 'json')
                display_df[col_name] = display_df[col_name].apply(
                    lambda x: JsonFormatter.format_json_column(x, default_mode)
                )
        
        return display_df


class JsonDataTable:
    """可复用的JSON数据表格组件"""
    
    def __init__(self, data, config=None, name:str=None, show_index=True, mode='native', display_mode_selector:bool=False):
        """
        初始化JSON数据表格
        
        Args:
            data (pd.DataFrame): 要显示的数据
            config (dict): 配置信息，包含json_columns等
            name (str): 组件名称，用于保存状态
            show_index (bool): 是否显示索引列，默认为True
            mode (str): 表格模式，'aggrid'或'native'，默认为'aggrid'
        """
        self.data = data
        self.config = config or {}
        self.cell_viewer = CellViewer()
        self._name = name or id(self)
        self.show_index = show_index
        self.mode = mode
        self._display_mode_selector = display_mode_selector
        
        # 添加数据和字段变化的追踪
        self._data_hash = self._compute_data_hash(data)
        self._cached_paths = {}  # 格式: {(data_hash, column_name): path}
        
    def _compute_data_hash(self, data):
        """计算数据的哈希值，用于检测数据变化"""
        try:
            # 使用数据的形状、列名和前几行数据来计算哈希
            shape_str = f"{data.shape}"
            columns_str = ",".join(sorted(data.columns.tolist()))
            # 取前3行数据的字符串表示（避免大数据集的性能问题）
            sample_data = data.head(3).to_string()
            return hash(shape_str + columns_str + sample_data)
        except Exception:
            return hash(str(data.shape) + str(data.columns.tolist()))

    @property
    def session_key(self):
        return f"json_table_{self._name}"
    
    def _get_cached_path(self, column_name):
        """获取指定列的缓存路径"""
        cache_key = (self._data_hash, column_name)
        return self._cached_paths.get(cache_key)
    
    def _set_cached_path(self, column_name, path):
        """设置指定列的缓存路径"""
        cache_key = (self._data_hash, column_name)
        self._cached_paths[cache_key] = path
    
    def _clear_cached_paths(self):
        """清除所有缓存的路径"""
        self._cached_paths.clear()
        
    def update_data(self, new_data):
        """更新数据，如果数据发生变化则清除缓存的路径"""
        new_hash = self._compute_data_hash(new_data)
        if new_hash != self._data_hash:
            self._clear_cached_paths()
            self._data_hash = new_hash
        self.data = new_data
        
    def display(self, page_size=20, height=600):
        """
        显示JSON数据表格
        
        Args:
            page_size (int): 每页显示的记录数
            height (int): 表格高度
        
        Returns:
            dict: 包含选中行和其他表格状态信息
        """
        # 显示模式切换控制
        if self._display_mode_selector:
            self._render_mode_selector()
        
        # 根据模式显示不同的表格
        if self.mode == 'native':
            return self._display_native_table(page_size, height)
        else:
            return self._display_aggrid_table(page_size, height)
    
    def _render_mode_selector(self):
        """渲染模式选择器"""
        col1, col2 = st.columns([1, 4])
        with col1:
            mode_options = [
                ('AgGrid表格', 'aggrid'),
                ('原生表格', 'native')
            ]
            selected_mode = st.selectbox(
                "表格模式",
                options=[mode[1] for mode in mode_options],
                format_func=lambda x: next(name for name, mode in mode_options if mode == x),
                index=0 if self.mode == 'aggrid' else 1,
                key=f"table_mode_{self.session_key}"
            )
            if selected_mode != self.mode:
                self.mode = selected_mode
                st.rerun()
    
    def _display_native_table(self, page_size, height):
        """
        使用原生st.data_editor显示表格
        
        Args:
            page_size (int): 每页显示的记录数
            height (int): 表格高度
        
        Returns:
            dict: 包含选中行和其他表格状态信息
        """
        # JSON列显示模式控制
        json_display_modes = self._render_json_display_controls()
        
        # 准备显示用的DataFrame
        display_df = self._prepare_display_dataframe(json_display_modes)
        
        # 添加选择列 - 如果有index列则在index列之后插入，否则在第一列插入
        if 'index' in display_df.columns:
            display_df.insert(1, '_select', False)
        else:
            display_df.insert(0, '_select', False)
        
        # 配置列类型
        column_config = {
            '_select': st.column_config.CheckboxColumn(
                '选择',
                help='选择行查看详情',
                default=False,
                width='small'
            )
        }
        
        # 为JSON列配置文本列以便显示格式化内容
        if 'json_columns' in self.config:
            for col_name in self.config['json_columns'].keys():
                if col_name in display_df.columns:
                    column_config[col_name] = st.column_config.TextColumn(
                        col_name,
                        width='large'
                    )
        
        # 隐藏原始索引列
        if '_original_index' in display_df.columns:
            column_config['_original_index'] = None
        
        # 如果显示索引列，配置索引列
        if self.show_index and 'index' in display_df.columns:
            column_config['index'] = st.column_config.NumberColumn(
                'Index',
                width='small',
                pinned=True  # 冻结列
            )
        
        # 使用st.data_editor显示表格
        edited_df = st.data_editor(
            display_df,
            column_config=column_config,
            width='stretch',
            hide_index=True,
            height=height,
            key=f"_data_editor_{self.session_key}_native"
        )
        
        # 获取选中的行
        selected_rows = edited_df[edited_df['_select'] == True].copy()
        if not selected_rows.empty:
            # 移除选择列以保持与AgGrid模式的一致性
            selected_rows = selected_rows.drop(columns=['_select'])
        
        # 创建与AgGrid兼容的响应对象
        class NativeGridResponse:
            def __init__(self, selected_rows, data):
                self.selected_rows = selected_rows
                self.data = data
        
        grid_response = NativeGridResponse(selected_rows, edited_df)
        
        # 显示选中行的JSON字段详情
        self._display_selected_rows_json(grid_response)
        
        result = {
            'grid_response': grid_response,
            'selected_rows': selected_rows if not selected_rows.empty else None,
            'display_df': display_df
        }
        
        # 显示总记录数
        st.caption(f"总共 {len(self.data)} 条记录")
        
        return result
    
    def _display_aggrid_table(self, page_size, height):
        """
        使用AgGrid显示表格（原有逻辑）
        
        Args:
            page_size (int): 每页显示的记录数
            height (int): 表格高度
        
        Returns:
            dict: 包含选中行和其他表格状态信息
        """
        # JSON列显示模式控制
        json_display_modes = self._render_json_display_controls()
        
        # 准备显示用的DataFrame
        display_df = self._prepare_display_dataframe(json_display_modes)
        
        # 创建和配置AgGrid
        grid_response = self._create_aggrid(display_df, page_size, height)
        
        # 显示选中行的JSON字段详情
        self._display_selected_rows_json(grid_response)
        
        result = {
            'grid_response': grid_response,
            'selected_rows': grid_response.selected_rows if hasattr(grid_response, 'selected_rows') else None,
            'display_df': display_df
        }
        
        # 显示总记录数
        st.caption(f"总共 {len(self.data)} 条记录")
        
        return result
    
    def _render_json_display_controls(self):
        """渲染JSON列显示模式控制"""
        json_display_modes = {}
        
        if 'json_columns' in self.config and self.config['json_columns']:
            st.subheader("🔧 JSON列显示设置")
            json_cols = st.columns(len(self.config['json_columns']))
            
            for idx, (col_name, col_config) in enumerate(self.config['json_columns'].items()):
                if col_name in self.data.columns:
                    with json_cols[idx]:
                        mode_options = [(mode['name'], mode['mode']) for mode in col_config['display_modes']]
                        selected_mode = st.selectbox(
                            f"{col_name} 显示模式",
                            options=[mode[1] for mode in mode_options],
                            format_func=lambda x: next(name for name, mode in mode_options if mode == x),
                            index=next(i for i, (_, mode) in enumerate(mode_options) 
                                     if mode == col_config.get('default_mode', 'json')),
                            key=f"_selectbox_display_mode_{col_name}_{self.session_key}"
                        )
                        json_display_modes[col_name] = selected_mode
        
        return json_display_modes
    
    def _prepare_display_dataframe(self, json_display_modes):
        """准备显示用的DataFrame"""
        display_df = self.data.copy()
        
        # 保持原始索引以便后续映射
        display_df = display_df.reset_index(drop=False)
        if 'index' in display_df.columns:
            display_df = display_df.rename(columns={'index': '_original_index'})
        else:
            display_df['_original_index'] = display_df.index
        
        # 如果启用了索引显示，且数据中没有'index'列，则显示_original_index为'index'列
        if self.show_index and 'index' not in self.data.columns:
            display_df['index'] = display_df['_original_index']
            # 将index列移动到第一列
            cols = ['index'] + [col for col in display_df.columns if col != 'index']
            display_df = display_df[cols]
        
        # 格式化JSON列
        if 'json_columns' in self.config:
            for col_name, col_config in self.config['json_columns'].items():
                if col_name in display_df.columns:
                    display_mode = json_display_modes.get(col_name, col_config.get('default_mode', 'json'))
                    display_df[col_name] = display_df[col_name].apply(
                        lambda x: JsonFormatter.format_json_column(x, display_mode)
                    )
        
        return display_df
    
    def _create_aggrid(self, display_df, page_size, height):
        """创建和配置AgGrid"""
        gb = GridOptionsBuilder.from_dataframe(display_df)
        
        # 配置分页
        gb.configure_pagination(
            paginationAutoPageSize=False, 
            paginationPageSize=page_size,
        )
        
        # gb.configure_selection('multiple', use_checkbox=True, header_checkbox=True, rowMultiSelectWithClick=True)
        # update_mode=GridUpdateMode.MODEL_CHANGED

        gb.configure_selection('single', use_checkbox=False)
        update_mode=GridUpdateMode.SELECTION_CHANGED
        
        # 隐藏原始索引列
        if '_original_index' in display_df.columns:
            gb.configure_column('_original_index', hide=True)
        
        # 如果显示索引列，配置索引列为第一列且冻结
        if self.show_index and 'index' in display_df.columns:
            gb.configure_column('index', headerName='Index', width=80, pinned='left')
        
        # 设置默认列配置
        gb.configure_default_column(
            editable=False,
            sorteable=True,
            filter=True,
            minWidth=120,
            # width=150,
            maxWidth=400,
            valueFormatter="typeof value === 'object' && value !== null ? JSON.stringify(value) : value"
        )
        
        # 为JSON列设置友好的宽度范围
        if 'json_columns' in self.config:
            for col_name in self.config['json_columns'].keys():
                if col_name in display_df.columns:
                    gb.configure_column(
                        col_name,
                        minWidth=200,
                        width=250,
                        maxWidth=400,
                        flex=0,
                        wrapText=True,
                        autoHeight=True,
                        resizable=True,
                        valueFormatter="typeof value === 'object' ? JSON.stringify(value) : value"
                    )
        
        # 配置网格选项
        gb.configure_grid_options(
            suppressContextMenu=True
        )
        
        gridOptions = gb.build()
        
        return AgGrid(
            display_df,
            gridOptions=gridOptions,
            data_return_mode=DataReturnMode.FILTERED_AND_SORTED,
            update_mode=update_mode,
            fit_columns_on_grid_load=False,
            height=height,
            width='100%',
            enable_enterprise_modules=False,
            allow_unsafe_jscode=True,
            reload_data=False,
            key=f"_aggrid_{self.session_key}"
        )

    def _on_selected_cols_changed(self):
        """当选中的列发生变化时的回调函数"""
        # 标记选中列发生了变化
        st.session_state[('selected_cols_changed', self.session_key)] = True
    
    def _get_selected_cols_session_key(self):
        """获取选中列的session state key"""
        return ('selected_cols', self.session_key)
    
    def _get_selected_cols_from_session(self, available_cols):
        """从session state获取选中的列，并过滤出仍然可用的列"""
        session_key = self._get_selected_cols_session_key()
        saved_cols = st.session_state.get(session_key, [])
        
        # 过滤出仍然在available_cols中的列
        valid_cols = [col for col in saved_cols if col in available_cols]
        return valid_cols
    
    def _save_selected_cols_to_session(self, selected_cols):
        """保存选中的列到session state"""
        session_key = self._get_selected_cols_session_key()
        st.session_state[session_key] = selected_cols

    def _get_selected_row_cell_data(self, selected_row:pd.Series, col):
        # 获取原始数据值（通过_original_index获取未格式化的原始值）
        if '_original_index' in selected_row:
            original_index = selected_row['_original_index']
            if original_index < len(self.data):
                # 如果请求的是'index'列，但原始数据中没有这一列，返回_original_index的值
                if col == 'index' and 'index' not in self.data.columns:
                    return original_index
                # 如果原始数据中有这一列，则返回原始值
                if col in self.data.columns:
                    return self.data.iloc[original_index][col]
        return selected_row[col]
    
    def _display_selected_rows_json(self, grid_response):
        """显示选中行的JSON字段详情"""
        if not hasattr(grid_response, 'selected_rows') or not is_not_empty(grid_response.selected_rows):
            return
        
        selected_rows:pd.DataFrame = grid_response.selected_rows
        if not is_not_empty(selected_rows):
            return

        st.subheader("📋 选中行的JSON字段详情")
        # 创建两列布局的下拉选择
        col1, col2 = st.columns(2)
        
        with col1:
            # 将col1拆分成两栏
            col1_1, col1_2 = st.columns(2)
            
            with col1_1:
                # 行选择下拉
                row_options = []
                for i in range(len(selected_rows)):
                    row = selected_rows.iloc[i]
                    if 'index' in row and pd.notna(row['index']):
                        row_options.append(f"第{i+1}行 (index: {row['index']})")
                    else:
                        row_options.append(f"第{i+1}行")
                
                selected_row_idx = st.selectbox(
                    "选择行",
                    options=list(range(len(selected_rows))),
                    format_func=lambda x: row_options[x],
                    key=f"{self.session_key}_row_selector"
                )
            
            with col1_2:
                # 行偏移量输入 - 针对整个DataFrame
                if selected_row_idx is not None:
                    # 获取当前选中行在原始DataFrame中的索引
                    selected_row = selected_rows.iloc[selected_row_idx]
                    current_original_index = int(selected_row['_original_index']) if '_original_index' in selected_row else selected_row_idx
                    
                    # 计算偏移量范围（基于整个DataFrame）
                    min_offset = -current_original_index
                    max_offset = len(self.data) - 1 - current_original_index
                    
                    row_offset = st.number_input(
                        "行偏移量",
                        min_value=min_offset,
                        max_value=max_offset,
                        value=0,
                        step=1,
                        help=f"相对于DataFrame的偏移，范围: [{min_offset}, {max_offset}]",
                        key=f"{self.session_key}_row_offset"
                    )
                    
                    # 计算在整个DataFrame中的实际行索引
                    target_dataframe_index = current_original_index + row_offset
                else:
                    target_dataframe_index = None

        # 获取JSON列配置，如果未配置则自动检测
        # if 'json_columns' in self.config and self.config['json_columns']:
        #     json_columns = list(self.config['json_columns'].keys())
        # else:
        # 自动检测可查看详情的列：包括JSON、对象类型和长字符串
        json_columns = []
        if target_dataframe_index is not None:
            # 从整个DataFrame中获取目标行数据
            target_row_data = self.data.iloc[target_dataframe_index]
            for col in self.data.columns:
                cell_value = target_row_data[col]
                if self._is_viewable_content(cell_value):
                    json_columns.append(col)
        
        # 过滤出在DataFrame中存在的JSON列
        available_json_cols = [col for col in json_columns if col in self.data.columns]
        
        with col2:
            # 支持多选可查看列（最多两列）
            # 从session state获取之前选择的列作为默认值
            saved_cols = self._get_selected_cols_from_session(available_json_cols)
            # 如果没有保存的选择或保存的选择已无效，使用第一个可用列作为默认值
            default_cols = saved_cols if saved_cols else ([available_json_cols[0]] if available_json_cols else [])
            
            selected_cols = st.multiselect(
                "选择要查看详情的列（最多2列）",
                options=available_json_cols,
                default=default_cols,
                max_selections=2,
                key=f"{self.session_key}_col_selector",
                on_change=self._on_selected_cols_changed
            )
            
            # 处理选中列的变化
            if st.session_state.get(('selected_cols_changed', self.session_key)):
                # 删除变化标记
                del st.session_state[('selected_cols_changed', self.session_key)]
                # 保存当前选择到session state
                self._save_selected_cols_to_session(selected_cols)
        
        # 显示选中单元格的JSON数据
        if target_dataframe_index is not None and selected_cols:
            # 从整个DataFrame中获取目标行数据
            target_row_data = self.data.iloc[target_dataframe_index]
            
            if len(selected_cols) == 1:
                # 单列显示
                selected_col = selected_cols[0]
                original_value = target_row_data[selected_col]
                
                if self._is_viewable_content(original_value):
                    row_display = f"第{target_dataframe_index + 1}行 (DataFrame索引: {target_dataframe_index})"
                    
                    with st.expander(f"{row_display} - {selected_col}", expanded=True):
                        self._display_content(original_value, column_name=selected_col)
                else:
                    st.info("选中的单元格不包含可查看的内容")
            
            elif len(selected_cols) == 2:
                # 双列并排显示
                left_col, right_col = st.columns(2)
                
                for idx, selected_col in enumerate(selected_cols):
                    original_value = target_row_data[selected_col]
                    
                    with (left_col if idx == 0 else right_col):
                        if self._is_viewable_content(original_value):
                            row_display = f"第{target_dataframe_index + 1}行 (DataFrame索引: {target_dataframe_index})"
                            
                            st.subheader(f"{row_display} - {selected_col}")
                            self._display_content(original_value, column_name=selected_col)
                        else:
                            st.info(f"{selected_col}: 不包含可查看的内容")
    
    def _display_json_content(self, value):
        """显示JSON内容的通用方法"""
        # 使用CSS定义滚动容器样式，针对Streamlit的JSON组件
        st.markdown("""
        <style>
        /* 针对JSON组件的滚动容器 */
        div[data-testid="stJson"] {
            max-height: 90vh;
            overflow-y: auto;
            border: 1px solid #e0e0e0;
            border-radius: 5px;
            padding: 10px;
            background-color: #fafafa;
            margin: 5px 0;
        }
        /* 针对文本组件的滚动容器 */
        div[data-testid="stText"] {
            max-height: 90vh;
            overflow-y: auto;
            border: 1px solid #e0e0e0;
            border-radius: 5px;
            padding: 10px;
            background-color: #fafafa;
            margin: 5px 0;
        }
        </style>
        """, unsafe_allow_html=True)
        try:
            if isinstance(value, str):
                try:
                    parsed_json = json.loads(value)
                    st.code(parsed_json, language="json", className="scrollable-code")
                    # st.json(parsed_json)
                except json.JSONDecodeError:
                    st.text(value)
            elif isinstance(value, np.ndarray):
                # 将numpy数组转换为列表
                array_data = value.tolist()
                st.json(array_data)
            elif isinstance(value, (dict, list)):
                st.json(value)
            else:
                st.text(str(value))
        except Exception as e:
            st.error(f"显示数据时出错: {e}")
            st.text(str(value))
    
    def _is_valid_json_data(self, value):
        """检查是否为有效的JSON数据"""
        if value is None:
            return False
        
        if isinstance(value, str):
            if value.strip() == "":
                return False
            try:
                json.loads(value)
                return True
            except json.JSONDecodeError:
                return False
        elif isinstance(value, (dict, list, np.ndarray)):
            return True
        else:
            return False
    
    def _is_viewable_content(self, value):
        """检查是否为可查看详情的内容（JSON数据、对象类型或长字符串）"""
        if value is None:
            return False
        
        # JSON数据检查
        if self._is_valid_json_data(value):
            return True
        
        # 对象类型检查（除了基本的数值类型）
        if isinstance(value, (dict, list, tuple, set, np.ndarray)):
            return True
        
        # 长字符串检查（超过100字符）
        if isinstance(value, str) and len(value.strip()) > 100:
            return True
        
        # 其他复杂对象类型
        if hasattr(value, '__dict__') and not isinstance(value, (int, float, str, bool)):
            return True
            
        return False
    
    def _display_content(self, value, enable_key_path=True, column_name=None):
        """显示内容的通用方法，根据内容类型选择合适的显示方式"""
        # 使用CSS定义滚动容器样式
        st.markdown("""
        <style>
        /* 针对JSON组件的滚动容器 */
        div[data-testid="stJson"] {
            max-height: 90vh;
            overflow-y: auto;
            border: 1px solid #e0e0e0;
            border-radius: 5px;
            padding: 10px;
            background-color: #fafafa;
            margin: 5px 0;
        }
        /* 针对代码组件的滚动容器 */
        div[data-testid="stCode"] {
            max-height: 90vh;
            overflow-y: auto;
            border: 1px solid #e0e0e0;
            border-radius: 5px;
            margin: 5px 0;
        }
        /* 针对文本组件的滚动容器 */
        div[data-testid="stText"] {
            max-height: 90vh;
            overflow-y: auto;
            border: 1px solid #e0e0e0;
            border-radius: 5px;
            padding: 10px;
            background-color: #fafafa;
            margin: 5px 0;
        }
        </style>
        """, unsafe_allow_html=True)
        
        def _render_content_settings(field_type: str, content_value, unique_suffix: str = ""):
            """渲染内容设置的内部函数"""
            settings_data = {}
            
            if field_type == "json" and enable_key_path and self._is_valid_json_data(content_value):
                # 使用JsonPathExtractor组件替代内联实现
                extractor_key = f"json_path_extractor_{id(content_value)}{unique_suffix}"
                if column_name:
                    extractor_key = f"json_path_extractor_{column_name}_{self._data_hash}"
                
                extractor = JsonPathExtractor(key_prefix=extractor_key)
                
                # 尝试从缓存中获取之前的路径作为默认值
                cached_path = None
                if column_name:
                    cached_path = self._get_cached_path(column_name)
                
                # 如果有缓存路径，预填充到session state中
                if cached_path and f"{extractor_key}_path_input" not in st.session_state:
                    st.session_state[f"{extractor_key}_path_input"] = cached_path
                
                # 渲染JsonPathExtractor
                extraction_result = extractor.render(content_value, expanded=False)
                
                # 缓存成功使用的路径
                if extraction_result['success'] and extraction_result['path_used'] and column_name:
                    self._set_cached_path(column_name, extraction_result['path_used'])
                
                settings_data['extracted_value'] = extraction_result['extracted_data']
            
            elif field_type == "code":
                # 代码显示设置
                with st.expander("⚙️ 代码显示设置", expanded=False):
                    col1, col2, col3 = st.columns(3)
                    with col1:
                        # 语言选择
                        supported_languages = CodeFormatter.get_supported_languages()
                        language_options = list(supported_languages.keys())
                        
                        # 自动检测语言
                        if isinstance(content_value, list):
                            auto_detected = CodeFormatter.auto_detect_language(content_value[0]) if content_value else 'text'
                        else:
                            auto_detected = CodeFormatter.auto_detect_language(str(content_value))
                        default_index = language_options.index(auto_detected) if auto_detected in language_options else language_options.index('text')
                        
                        selected_language = st.selectbox(
                            "选择语言类型",
                            options=language_options,
                            format_func=lambda x: supported_languages[x],
                            index=default_index,
                            key=f"code_language_{id(content_value)}{unique_suffix}"
                        )
                        settings_data['language'] = selected_language
                    
                    with col2:
                        # 自动换行设置
                        line_wrap = st.toggle(
                            "自动换行",
                            value=True,
                            key=f"code_wrap_{id(content_value)}{unique_suffix}"
                        )
                        settings_data['line_wrap'] = line_wrap
                    
                    with col3:
                        # 代码美化设置
                        beautify = st.toggle(
                            "自动美化",
                            value=True,
                            key=f"code_beautify_{id(content_value)}{unique_suffix}"
                        )
                        settings_data['beautify'] = beautify
            
            return settings_data
        
        # 判断内容类型并应用相应的设置
        if enable_key_path and self._is_valid_json_data(value):
            # JSON类型内容：先显示JSON路径提取设置
            settings = _render_content_settings("json", value)
            display_value = settings.get('extracted_value', value)
        else:
            # 非JSON内容：直接使用原始值
            display_value = value
        
        # 显示提取后的内容
        self._display_extracted_content_with_settings(display_value, _render_content_settings)
    
    def _display_extracted_content_with_settings(self, display_value, settings_renderer):
        """显示提取后的内容，根据内容类型应用相应设置"""
        try:
            # 处理路径提取后的不同数据类型
            if isinstance(display_value, str):
                # 字符串类型：使用增强的代码显示功能
                settings = settings_renderer("code", display_value, "_str")
                self._display_code_content_with_settings(display_value, settings)
            elif isinstance(display_value, list) and all(isinstance(item, str) for item in display_value):
                # 字符串列表：使用可折叠的代码块展示
                settings = settings_renderer("code", display_value, "_list")
                self._display_string_list_content_with_settings(display_value, settings)
            elif self._is_valid_json_data(display_value):
                # JSON数据：使用st.json显示
                if isinstance(display_value, str):
                    try:
                        parsed_json = json.loads(display_value)
                        st.json(parsed_json)
                        return
                    except json.JSONDecodeError:
                        pass
                elif isinstance(display_value, np.ndarray):
                    array_data = display_value.tolist()
                    st.json(array_data)
                    return
                elif isinstance(display_value, (dict, list)):
                    st.json(display_value)
                    return
            else:
                # 其他类型：转为字符串显示
                settings = settings_renderer("code", str(display_value), "_other")
                self._display_code_content_with_settings(str(display_value), settings)
                
        except Exception as e:
            st.error(f"显示数据时出错: {e}")
            st.text(str(display_value))
    
    def _display_code_content_with_settings(self, content: str, settings: dict):
        """显示单个代码内容，使用提供的设置"""
        if not content:
            st.info("内容为空")
            return
        
        language = settings.get('language', 'text')
        line_wrap = settings.get('line_wrap', True)
        beautify = settings.get('beautify', True)
        
        # 渲染代码块
        self._render_code_block(content, language, line_wrap, beautify)
    
    def _display_string_list_content_with_settings(self, string_list: list, settings: dict):
        """显示字符串列表内容，使用提供的设置"""
        if not string_list:
            st.info("列表为空")
            return
        
        language = settings.get('language', 'text')
        line_wrap = settings.get('line_wrap', True)
        beautify = settings.get('beautify', True)
        
        # 显示每个字符串
        for i, content in enumerate(string_list):
            with st.expander(f"📄 第 {i+1} 项", expanded=i < 3):  # 默认只展开前3项
                self._render_code_block(content, language, line_wrap, beautify)
    
    def _render_code_block(self, content: str, language: str, line_wrap: bool, beautify: bool):
        """渲染代码块的内部函数"""
        try:
            # 应用代码格式化
            if beautify:
                formatted_content = CodeFormatter.format_code(content, language, beautify)
            else:
                formatted_content = content
            
            # 应用换行设置的CSS
            if line_wrap:
                st.markdown("""
                <style>
                div[data-testid="stCode"] > pre code {
                    white-space: pre-wrap !important;
                    word-wrap: break-word !important;
                }
                </style>
                """, unsafe_allow_html=True)
            else:
                st.markdown("""
                <style>
                div[data-testid="stCode"] > pre code {
                    white-space: pre !important;
                    overflow-x: auto !important;
                }
                </style>
                """, unsafe_allow_html=True)
            
            # 显示格式化后的代码
            st.code(formatted_content, language=language)
            
            # 显示原始内容长度和格式化后长度的信息
            if beautify and formatted_content != content:
                st.caption(f"📊 原始长度: {len(content)} 字符，格式化后: {len(formatted_content)} 字符")
            else:
                st.caption(f"📊 内容长度: {len(content)} 字符")
                
        except Exception as e:
            st.error(f"代码渲染失败: {e}")
            st.code(content, language='text')

    def _display_json_field_content(self, col_name, field_data):
        """显示JSON字段的内容"""
        for data_item in field_data:
            row_index = data_item['row_index']
            value = data_item['value']
            
            with st.expander(f"第{row_index + 1}行 - {col_name}", expanded=True):
                try:
                    if isinstance(value, str):
                        try:
                            parsed_json = json.loads(value)
                            st.json(parsed_json)
                        except json.JSONDecodeError:
                            st.text(value)
                    elif isinstance(value, np.ndarray):
                        # 将numpy数组转换为列表
                        array_data = value.tolist()
                        st.json(array_data)
                    elif isinstance(value, (dict, list)):
                        st.json(value)
                    else:
                        st.text(str(value))
                except Exception as e:
                    st.error(f"显示数据时出错: {e}")
                    st.text(str(value))


def create_json_table(data, config=None, mode='aggrid', show_index=True):
    """
    创建JSON数据表格的便捷函数
    
    Args:
        data (pd.DataFrame): 要显示的数据
        config (dict): 配置信息
        mode (str): 表格模式，'aggrid'或'native'，默认为'aggrid'
        show_index (bool): 是否显示索引列，默认为True
    
    Returns:
        JsonDataTable: JSON数据表格实例
    """
    return JsonDataTable(data, config, mode=mode, show_index=show_index)