"""
Individual Record Update View

Provides record-by-record field comparison and update controls.
"""

import streamlit as st
import pandas as pd
from typing import List, Dict, Any
from services.update_engine import UpdateEngine
from bson import ObjectId


def _render_individual_record_updates(
    duplicates: List[Dict[str, Any]],
    collection_name: str,
    mongo_service,
    update_engine: UpdateEngine
):
    """
    Render individual record-level field comparison and updates.
    
    Args:
        duplicates: List of duplicate records
        collection_name: Name of the collection
        mongo_service: MongoService instance
        update_engine: UpdateEngine instance
    """
    st.markdown("### 📝 Individual Record Updates")
    
    st.info(f"""
    **Individual Record Mode**
    - Review each record separately
    - Select fields to update for each record
    - Apply updates per record or in bulk
    
    Total records: **{len(duplicates)}**
    """)
    
    # Initialize session state for individual updates
    if 'individual_update_decisions' not in st.session_state:
        st.session_state.individual_update_decisions = {}
    
    # Record selector
    st.markdown("#### Select Record to Review")
    
    col1, col2, col3 = st.columns([2, 1, 1])
    
    with col1:
        # Create record options with business key info
        record_options = []
        for idx, dup in enumerate(duplicates):
            match_method = dup.get('match_method', 'unknown')
            matching_key = dup.get('matching_key', 'N/A')
            record_options.append(f"Record #{idx + 1}: {matching_key}")
        
        selected_record_idx = st.selectbox(
            "Choose a record",
            options=range(len(duplicates)),
            format_func=lambda i: record_options[i],
            key='individual_record_selector'
        )
    
    with col2:
        st.metric("Current Record", f"{selected_record_idx + 1}/{len(duplicates)}")
    
    with col3:
        # Navigation buttons
        col_prev, col_next = st.columns(2)
        with col_prev:
            if st.button("⬅️ Prev", disabled=selected_record_idx == 0, use_container_width=True):
                st.session_state.individual_record_selector = selected_record_idx - 1
                st.rerun()
        with col_next:
            if st.button("Next ➡️", disabled=selected_record_idx == len(duplicates) - 1, use_container_width=True):
                st.session_state.individual_record_selector = selected_record_idx + 1
                st.rerun()
    
    st.markdown("---")
    
    # Get selected record
    selected_dup = duplicates[selected_record_idx]
    json_record = selected_dup['json_record']
    db_record = selected_dup['db_record']
    
    # Show match info
    match_method = selected_dup.get('match_method', 'unknown')
    matching_key = selected_dup.get('matching_key', 'N/A')
    
    match_icon = "🔑" if match_method == 'primary_key' else "🔍"
    match_label = "Primary Key" if match_method == 'primary_key' else "Alternative Key"
    
    st.info(f"{match_icon} **Matched by {match_label}:** {matching_key}")
    
    # Compare fields
    from services.import_preview_engine import ImportPreviewEngine
    preview_engine = ImportPreviewEngine()
    
    # Build comparison for this single record
    comp_df = preview_engine.build_duplicate_comparison_dataframe([selected_dup])
    
    if comp_df.empty:
        st.warning("No field differences found")
        return
    
    # Initialize decisions for this record
    record_key = f"record_{selected_record_idx}"
    if record_key not in st.session_state.individual_update_decisions:
        # Default: update new and different fields
        default_decisions = {}
        for _, row in comp_df.iterrows():
            field = row['field']
            status = row['status']
            if status in ['new', 'different']:
                default_decisions[field] = 'update'
            else:
                default_decisions[field] = 'skip'
        st.session_state.individual_update_decisions[record_key] = default_decisions
    
    # Quick action buttons for this record
    st.markdown("#### Quick Actions for This Record")
    
    col1, col2, col3, col4 = st.columns(4)
    
    with col1:
        if st.button("✅ Update All", key=f"update_all_{selected_record_idx}", use_container_width=True):
            for field in st.session_state.individual_update_decisions[record_key].keys():
                st.session_state.individual_update_decisions[record_key][field] = 'update'
            st.rerun()
    
    with col2:
        if st.button("❌ Skip All", key=f"skip_all_{selected_record_idx}", use_container_width=True):
            for field in st.session_state.individual_update_decisions[record_key].keys():
                st.session_state.individual_update_decisions[record_key][field] = 'skip'
            st.rerun()
    
    with col3:
        if st.button("✅ Update New", key=f"update_new_{selected_record_idx}", use_container_width=True):
            for _, row in comp_df.iterrows():
                field = row['field']
                if row['status'] == 'new':
                    st.session_state.individual_update_decisions[record_key][field] = 'update'
            st.rerun()
    
    with col4:
        if st.button("✅ Update Different", key=f"update_diff_{selected_record_idx}", use_container_width=True):
            for _, row in comp_df.iterrows():
                field = row['field']
                if row['status'] == 'different':
                    st.session_state.individual_update_decisions[record_key][field] = 'update'
            st.rerun()
    
    st.markdown("---")
    
    # Display field comparison with checkboxes
    st.markdown("#### Field-by-Field Comparison")
    
    # Add decision column to dataframe
    comp_df['_update_decision'] = comp_df['field'].apply(
        lambda f: st.session_state.individual_update_decisions[record_key].get(f, 'skip')
    )
    
    # Color coding function
    def highlight_row(row):
        styles = []
        status = row.get('status', '')
        
        for col in comp_df.columns:
            if col == 'field':
                styles.append('font-weight: bold; background-color: #f5f5f5')
            elif col == 'status':
                if status == 'new':
                    styles.append('background-color: #4CAF50; color: white; font-weight: bold')
                elif status == 'different':
                    styles.append('background-color: #FF9800; color: white; font-weight: bold')
                elif status == 'missing_in_json':
                    styles.append('background-color: #f44336; color: white; font-weight: bold')
                elif status == 'match':
                    styles.append('background-color: #9E9E9E; color: white')
                else:
                    styles.append('')
            elif col == 'json_value':
                if status == 'new':
                    styles.append('background-color: #C8E6C9; color: #1B5E20; font-weight: bold')
                elif status == 'different':
                    styles.append('background-color: #BBDEFB; color: #0D47A1; font-weight: bold')
                else:
                    styles.append('background-color: #E3F2FD; color: #1565C0')
            elif col == 'db_value':
                if status == 'different':
                    styles.append('background-color: #FFE0B2; color: #E65100; font-weight: bold')
                elif status == 'missing_in_json':
                    styles.append('background-color: #FFCDD2; color: #B71C1C; font-weight: bold')
                else:
                    styles.append('background-color: #FFF3E0; color: #E65100')
            else:
                styles.append('')
        return styles
    
    # Display styled dataframe
    styled_df = comp_df.style.apply(highlight_row, axis=1)
    
    st.dataframe(
        styled_df,
        use_container_width=True,
        hide_index=True,
        height=400
    )
    
    st.markdown("""
    **🎨 Color Legend:**
    - 🟢 **NEW** (Green) - Field exists in JSON but NOT in MongoDB
    - 🟠 **DIFFERENT** (Orange) - Field value differs
    - 🔴 **MISSING** (Red) - Field exists in MongoDB but NOT in JSON
    - ⚪ **MATCH** (Gray) - Values are identical
    """)
    
    # Editable field selection
    st.markdown("#### Select Fields to Update")
    
    # Create checkboxes for each field
    update_count = 0
    for _, row in comp_df.iterrows():
        field = row['field']
        status = row['status']
        json_val = row['json_value']
        db_val = row['db_value']
        
        current_decision = st.session_state.individual_update_decisions[record_key].get(field, 'skip')
        
        col1, col2, col3, col4 = st.columns([3, 2, 2, 1])
        
        with col1:
            st.text(f"📌 {field}")
        
        with col2:
            st.text(f"JSON: {json_val}")
        
        with col3:
            st.text(f"DB: {db_val}")
        
        with col4:
            # Status badge
            if status == 'new':
                badge = "🟢 NEW"
            elif status == 'different':
                badge = "🟠 DIFF"
            elif status == 'match':
                badge = "⚪ MATCH"
            else:
                badge = "🔴 MISS"
            
            update_field = st.checkbox(
                badge,
                value=current_decision == 'update',
                key=f"field_update_{selected_record_idx}_{field}",
                label_visibility="visible"
            )
            
            if update_field:
                st.session_state.individual_update_decisions[record_key][field] = 'update'
                update_count += 1
            else:
                st.session_state.individual_update_decisions[record_key][field] = 'skip'
    
    st.markdown("---")
    
    # Summary and apply button
    st.markdown("#### Update Summary")
    
    col1, col2, col3 = st.columns(3)
    
    with col1:
        st.metric("Fields to Update", update_count)
    
    with col2:
        st.metric("Total Fields", len(comp_df))
    
    with col3:
        # Count total updates across all records
        total_updates = sum(
            sum(1 for decision in decisions.values() if decision == 'update')
            for decisions in st.session_state.individual_update_decisions.values()
        )
        st.metric("Total Updates (All Records)", total_updates)
    
    # Apply updates button
    if update_count > 0:
        st.warning(f"⚠️ Ready to update {update_count} field(s) in this record")
        
        col1, col2 = st.columns([1, 3])
        
        with col1:
            if st.button("🚀 Apply Updates to This Record", type="primary", use_container_width=True):
                _apply_individual_record_update(
                    selected_dup,
                    st.session_state.individual_update_decisions[record_key],
                    collection_name,
                    mongo_service
                )
        
        with col2:
            if st.button("🚀 Apply All Updates (All Records)", type="secondary", use_container_width=True):
                _apply_all_individual_updates(
                    duplicates,
                    st.session_state.individual_update_decisions,
                    collection_name,
                    mongo_service
                )


def _apply_individual_record_update(
    duplicate_record: Dict[str, Any],
    field_decisions: Dict[str, str],
    collection_name: str,
    mongo_service
):
    """Apply updates to a single record."""
    try:
        # Get fields to update
        fields_to_update = {
            field: duplicate_record['json_record'][field]
            for field, decision in field_decisions.items()
            if decision == 'update' and field in duplicate_record['json_record']
        }
        
        if not fields_to_update:
            st.warning("No fields selected for update")
            return
        
        # Get collection
        collection = mongo_service.get_collection(collection_name)
        
        if collection is None:
            st.error("❌ Collection not found")
            return
        
        # Prepare update
        db_id = duplicate_record['db_record']['_id']
        
        with st.spinner("Updating record..."):
            result = collection.update_one(
                {'_id': ObjectId(str(db_id))},
                {'$set': fields_to_update}
            )
            
            if result.modified_count > 0:
                st.success(f"✅ Successfully updated {len(fields_to_update)} field(s)")
                
                # Clear this record's decisions
                st.session_state.individual_update_decisions = {}
                st.rerun()
            else:
                st.warning("⚠️ No changes were made")
    
    except Exception as e:
        st.error(f"❌ Update failed: {str(e)}")


def _apply_all_individual_updates(
    duplicates: List[Dict[str, Any]],
    all_decisions: Dict[str, Dict[str, str]],
    collection_name: str,
    mongo_service
):
    """Apply updates to all records with pending decisions."""
    try:
        collection = mongo_service.get_collection(collection_name)
        
        if collection is None:
            st.error("❌ Collection not found")
            return
        
        updated_count = 0
        errors = []
        
        with st.spinner("Updating all records..."):
            for idx, duplicate_record in enumerate(duplicates):
                record_key = f"record_{idx}"
                
                if record_key not in all_decisions:
                    continue
                
                field_decisions = all_decisions[record_key]
                
                # Get fields to update
                fields_to_update = {
                    field: duplicate_record['json_record'][field]
                    for field, decision in field_decisions.items()
                    if decision == 'update' and field in duplicate_record['json_record']
                }
                
                if not fields_to_update:
                    continue
                
                try:
                    db_id = duplicate_record['db_record']['_id']
                    result = collection.update_one(
                        {'_id': ObjectId(str(db_id))},
                        {'$set': fields_to_update}
                    )
                    
                    if result.modified_count > 0:
                        updated_count += 1
                
                except Exception as e:
                    errors.append(f"Record #{idx + 1}: {str(e)}")
        
        if updated_count > 0:
            st.success(f"✅ Successfully updated {updated_count} record(s)")
            
            if errors:
                st.warning(f"⚠️ {len(errors)} update(s) failed:")
                for error in errors[:5]:
                    st.text(f"  - {error}")
            
            # Clear all decisions
            st.session_state.individual_update_decisions = {}
            st.session_state.comparison_results = None
            st.session_state.comparison_loaded = False
            
            st.info("💡 Reload the comparison to see updated results")
            st.rerun()
        else:
            st.warning("⚠️ No records were updated")
            if errors:
                for error in errors:
                    st.error(error)
    
    except Exception as e:
        st.error(f"❌ Failed to update: {str(e)}")
