"""
Editable Table Component

A reusable Streamlit component for displaying and editing MongoDB collection data.
Provides Excel-like editing capabilities with change tracking.

Key features:
- Display any DataFrame in an editable table
- Add/delete rows
- Edit cells inline
- Track changes (new/modified rows)
- Read-only ObjectId column
- Visual indicators for changes
"""

import streamlit as st
import pandas as pd
from typing import Optional, Dict, Any


def render_editable_table(
    collection_name: str,
    dataframe: pd.DataFrame,
    key_suffix: str = ""
) -> pd.DataFrame:
    """
    Render an editable table for a MongoDB collection.
    
    This component displays a DataFrame in an editable table format,
    allowing users to add, edit, and delete rows. Changes are tracked
    but not saved until the user explicitly applies them.
    
    Args:
        collection_name: Name of the collection being edited
        dataframe: DataFrame to display and edit
        key_suffix: Unique suffix for Streamlit widget keys
        
    Returns:
        Edited DataFrame with user changes
    """
    
    # Display collection info header
    st.subheader(f"📋 {collection_name}")
    
    # Show warning banner
    st.warning(
        "⚠️ **Changes are NOT saved until you click 'Apply Changes'**",
        icon="⚠️"
    )
    
    # Display document count
    total_rows = len(dataframe)
    st.info(f"**Total Documents:** {total_rows:,}")
    
    # Prepare column configuration
    column_config = _get_column_config(dataframe)
    
    # Render editable data editor
    edited_df = st.data_editor(
        dataframe,
        width="stretch",
        num_rows="dynamic",  # Allow adding/deleting rows
        column_config=column_config,
        hide_index=True,
        key=f"data_editor_{collection_name}_{key_suffix}"
    )
    
    # Show change summary
    _display_change_summary(dataframe, edited_df)
    
    return edited_df


def _get_column_config(dataframe: pd.DataFrame) -> Dict[str, Any]:
    """
    Generate column configuration for data editor.
    
    Makes _id column read-only and configures other columns appropriately.
    
    Args:
        dataframe: DataFrame to configure
        
    Returns:
        Dictionary of column configurations
    """
    column_config = {}
    
    for col in dataframe.columns:
        if col == '_id':
            # Make _id read-only
            column_config[col] = st.column_config.TextColumn(
                col,
                help="MongoDB ObjectId (read-only)",
                disabled=True,
                width="medium"
            )
        elif col in ['created_at', 'updated_at', 'imported_at']:
            # Date/time columns
            column_config[col] = st.column_config.TextColumn(
                col,
                help="Timestamp",
                width="medium"
            )
        else:
            # Default text column
            column_config[col] = st.column_config.TextColumn(
                col,
                width="medium"
            )
    
    return column_config


def _display_change_summary(
    original_df: pd.DataFrame,
    edited_df: pd.DataFrame
) -> None:
    """
    Display summary of changes between original and edited DataFrames.
    
    Shows counts of new, modified, and deleted rows.
    
    Args:
        original_df: Original DataFrame
        edited_df: Edited DataFrame
    """
    # Count changes
    original_count = len(original_df)
    edited_count = len(edited_df)
    
    # Calculate differences
    added_rows = max(0, edited_count - original_count)
    deleted_rows = max(0, original_count - edited_count)
    
    # Count modified rows (rough estimate)
    # This is a simple check - actual change detection is in data_service
    modified_rows = 0
    if '_id' in original_df.columns and '_id' in edited_df.columns:
        # Check for rows with same _id but different data
        common_ids = set(original_df['_id'].dropna()) & set(edited_df['_id'].dropna())
        
        for doc_id in common_ids:
            orig_row = original_df[original_df['_id'] == doc_id]
            edit_row = edited_df[edited_df['_id'] == doc_id]
            
            if not orig_row.empty and not edit_row.empty:
                # Compare row values (excluding _id)
                orig_vals = orig_row.iloc[0].drop('_id').to_dict()
                edit_vals = edit_row.iloc[0].drop('_id').to_dict()
                
                if orig_vals != edit_vals:
                    modified_rows += 1
    
    # Display change summary
    if added_rows > 0 or deleted_rows > 0 or modified_rows > 0:
        st.markdown("### 📊 Change Summary")
        
        col1, col2, col3 = st.columns(3)
        
        with col1:
            if added_rows > 0:
                st.metric("New Rows", added_rows, delta=added_rows, delta_color="normal")
            else:
                st.metric("New Rows", 0)
        
        with col2:
            if modified_rows > 0:
                st.metric("Modified Rows", modified_rows, delta=modified_rows, delta_color="normal")
            else:
                st.metric("Modified Rows", 0)
        
        with col3:
            if deleted_rows > 0:
                st.metric("Deleted Rows", deleted_rows, delta=-deleted_rows, delta_color="inverse")
            else:
                st.metric("Deleted Rows", 0)
    else:
        st.info("ℹ️ No changes detected")


def render_change_preview(preview_data: Dict[str, Any]) -> None:
    """
    Render detailed preview of changes before applying.
    
    Shows exactly what will be inserted, updated, and deleted.
    
    Args:
        preview_data: Dictionary with change details from data_service
    """
    st.markdown("### 🔍 Change Preview")
    
    # Summary metrics
    col1, col2, col3 = st.columns(3)
    
    with col1:
        st.metric("New Documents", preview_data['new_count'])
    
    with col2:
        st.metric("Updated Documents", preview_data['updated_count'])
    
    with col3:
        st.metric("Deleted Documents", preview_data['deleted_count'])
    
    # Detailed changes
    if preview_data['new_count'] > 0:
        with st.expander(f"📄 New Documents ({preview_data['new_count']})", expanded=True):
            for i, doc in enumerate(preview_data['new_docs'], 1):
                st.json(doc, expanded=False)
    
    if preview_data['updated_count'] > 0:
        with st.expander(f"✏️ Updated Documents ({preview_data['updated_count']})", expanded=True):
            for update in preview_data['updated_docs']:
                st.markdown(f"**Document ID:** `{update['_id']}`")
                st.json(update['updates'], expanded=False)
                st.markdown("---")
    
    if preview_data['deleted_count'] > 0:
        with st.expander(f"🗑️ Deleted Documents ({preview_data['deleted_count']})", expanded=True):
            for doc_id in preview_data['deleted_ids']:
                st.markdown(f"- `{doc_id}`")
