import narwhals as nw
import json
import webbrowser
import tempfile
from importlib import resources

def show(df):
    """Displays any Narwhals-compatible DataFrame in a browser using Tabulator.js."""

    data = list(nw.from_native(df).iter_rows(named=True))

    tabulator = {}
    for ext in ['js', 'css']:
        # Try installed package location first
        try:
            with resources.files('tablescope').joinpath(f'static/tabulator.min.{ext}').open('r') as f:
                tabulator[ext] = f.read()
        except (FileNotFoundError, OSError):
            # Fall back to development location
            try:
                with open(f'static/tabulator.min.{ext}', 'r') as f:
                    tabulator[ext] = f.read()
            except FileNotFoundError as e:
                raise FileNotFoundError(
                    f"Could not find tabulator.min.{ext} in either the installed package "
                    "or the development directory. Make sure the static files are present."
                ) from e
    
    # Dynamically generate column definitions with appropriate editors
    columns = []
    for col in df.columns:
        # Get a sample value to determine type
        sample = data[0][col] if data else None
        
        col_def = {
            "title": col,
            "field": col,
            "editor": True,  # Enable editing
            "headerFilter": False,  # Start with filters hidden
            "minWidth": 150,  # Minimum column width
            "resizable": True,  # Allow column resizing
        }
        
        if isinstance(sample, (int, float)):
            col_def["editor"] = "number"
            col_def["editorParams"] = {
                "selectContents": True  # Select all content when editing
            }
            col_def["headerFilter"] = "minMax"  # Use our registered custom editor
            col_def["headerFilterFunc"] = "minMaxFilterFunction"  # Use our custom filter function
            col_def["headerFilterLiveFilter"] = False  # Update on enter/blur rather than every keystroke
        else:
            col_def["editor"] = "input"
            col_def["editorParams"] = {
                "selectContents": True
            }
            col_def["headerFilter"] = "input"  # Standard text filter
            col_def["headerFilterPlaceholder"] = ""
        
        columns.append(col_def)

    html = f"""
    <!DOCTYPE html>
    <html>
    <head>
        <title>Table View</title>
        <style>
            {tabulator['css']}
            .controls-container {{
                padding: 20px;
                max-width: 1200px;
                margin: 0 auto;
            }}
            .table-controls {{
                max-width: 1200px;
                margin: 0 auto;
                display: grid;
                grid-template-columns: auto minmax(200px, 400px) auto;
                gap: 16px;
                align-items: center;
            }}
            .control-group {{
                display: flex;
                gap: 8px;
                justify-self: end;
            }}
            .table-controls input {{
                padding: 8px 12px;
                border: 1px solid #ddd;
                border-radius: 4px;
                font-size: 14px;
                background: white;
                width: 100%;
            }}
            .table-controls input:focus {{
                outline: none;
                border-color: #666;
                box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1);
            }}
            .table-controls select, .table-controls button {{
                padding: 8px 12px;
                background: white;
                border: 1px solid #ddd;
                border-radius: 4px;
                cursor: pointer;
                font-size: 14px;
                color: #333;
                min-width: 120px;
            }}
            .table-controls select option:first-child {{
                color: #757575;
            }}
            .table-controls select {{
                padding-right: 30px;  /* Extra space for the dropdown arrow */
                appearance: none;  /* Remove default arrow */
                background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
                background-repeat: no-repeat;
                background-position: right 8px center;
                background-size: 16px;
            }}
            .table-controls select:hover, .table-controls button:hover {{
                background-color: #f8f8f8;
                border-color: #999;
            }}
            .table-controls select:focus {{
                outline: none;
                border-color: #666;
                box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1);
            }}
            /* Style all header filter inputs consistently */
            .tabulator-header-filter {{
                padding: 4px !important;
            }}
            .tabulator-header-filter input {{
                padding: 4px 8px !important;
                border: 1px solid #ddd !important;
                border-radius: 4px !important;
                font-size: 12px !important;
                height: auto !important;
                box-sizing: border-box !important;
            }}
            /* Styles for min-max filter inputs */
            .header-filter-min-max {{
                display: flex;
                gap: 4px;
            }}
            .header-filter-min-max input {{
                width: 50%;
            }}
            /* Hide number input spinners */
            .header-filter-min-max input[type="number"]::-webkit-inner-spin-button,
            .header-filter-min-max input[type="number"]::-webkit-outer-spin-button {{
                -webkit-appearance: none;
                margin: 0;
            }}
            .header-filter-min-max input[type="number"] {{
                -moz-appearance: textfield;
            }}
            .tabulator-header-filter input:focus {{
                outline: none !important;
                border-color: #666 !important;
                box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1) !important;
            }}
            #table {{
                margin: 20px;
                max-width: 1200px;
            }}
            /* Override hover styles to maintain row colors */
            .tabulator-row.tabulator-selectable:hover {{
                background-color: #fff !important;
            }}
            .tabulator-row.tabulator-selectable.tabulator-row-even:hover {{
                background-color: #efefef !important;
            }}
        </style>
        <script>{tabulator['js']}</script>
    </head>
    <body>
        <div class="controls-container">
            <div class="table-controls">
                <select id="group-field">
                    <option value="">Group by...</option>
                    {' '.join(f'<option value="{col["field"]}">{col["title"]}</option>' for col in columns)}
                </select>
                <input type="text" id="search" placeholder="Search...">
                <div class="control-group">
                    <button id="download-csv">Download CSV</button>
                    <button id="download-json">Download JSON</button>
                </div>
            </div>
        </div>
        <div id="table"></div>
        <script>
            // Define the min/max filter function
            function minMaxFilterFunction(headerValue, rowValue, rowData, filterParams) {{
                if (rowValue === null || rowValue === undefined) return false;
                
                var value = parseFloat(rowValue);
                if (isNaN(value)) return false;

                if (headerValue.min !== "" && value < parseFloat(headerValue.min)) return false;
                if (headerValue.max !== "" && value > parseFloat(headerValue.max)) return false;
                
                return true;
            }}

            // Define the min/max filter editor
            function minMaxFilterEditor(cell, onRendered, success, cancel, editorParams) {{
                var container = document.createElement("div");
                container.className = "header-filter-min-max";

                var min = document.createElement("input");
                min.setAttribute("type", "number");
                min.setAttribute("placeholder", "Min");
                min.style.width = "50%";

                var max = document.createElement("input");
                max.setAttribute("type", "number");
                max.setAttribute("placeholder", "Max");
                max.style.width = "50%";

                function buildValues() {{
                    success({{
                        min: min.value,
                        max: max.value
                    }});
                }}

                function keypress(e) {{
                    if (e.key === "Enter") {{
                        buildValues();
                    }}
                    if (e.key === "Escape") {{
                        cancel();
                    }}
                }}

                min.addEventListener("change", buildValues);
                min.addEventListener("blur", buildValues);
                min.addEventListener("keydown", keypress);

                max.addEventListener("change", buildValues);
                max.addEventListener("blur", buildValues);
                max.addEventListener("keydown", keypress);

                container.appendChild(min);
                container.appendChild(max);

                return container;
            }}

            var data = {json.dumps(data)};
            var columns = {json.dumps(columns)};

            // Update column definitions to use the editor function directly
            columns.forEach(function(col) {{
                if (col.headerFilter === "minMax") {{
                    col.headerFilter = minMaxFilterEditor;
                    col.headerFilterFunc = minMaxFilterFunction;
                }}
            }});

            var table = new Tabulator("#table", {{
                data: data,
                layout: "fitDataTable",
                columns: columns,
                movableColumns: true,       // Allow column reordering
                clipboard: true,            // Enable copy to clipboard
                history: true,              // Enable undo/redo actions
                headerFilter: true,         // Show filters by default
                editTrigger: "dblclick",    // Double click to edit
                selectable: true,           // Enable row selection
                groupBy: null,              // Initial grouping
                rowHover: false,            // Disable row hover effect
                groupHeader: function(value, count, data, group) {{
                    return value + ' <span style="color: #666;">(' + count + ' items)</span>';
                }}
            }});

            // Setup grouping control
            document.getElementById("group-field").addEventListener("change", function(e) {{
                table.setGroupBy(e.target.value || false);
            }});

            // Custom filter function that searches across all fields
            function matchAny(data, filterParams) {{
                if (!filterParams.value) return true;
                
                const searchTerm = filterParams.value.toLowerCase();
                
                for (var key in data) {{
                    const cellValue = String(data[key]).toLowerCase();
                    if (cellValue.includes(searchTerm)) {{
                        return true;
                    }}
                }}
                
                return false;
            }}

            // Setup search functionality
            document.getElementById("search").addEventListener("input", function(e) {{
                table.setFilter(matchAny, {{value: e.target.value}});
            }});

            // Setup download buttons
            document.getElementById("download-csv").addEventListener("click", function() {{
                table.download("csv", "data.csv");
            }});

            document.getElementById("download-json").addEventListener("click", function() {{
                table.download("json", "data.json");
            }});
        </script>
    </body>
    </html>
    """

    with tempfile.NamedTemporaryFile(mode='w', suffix=".html", delete=False) as f:
        f.write(html)
        filepath = f.name

    try:
        if webbrowser.open(f"file://{filepath}"):
            return

    except Exception as e:
        print(f"Error opening browser: {e}")
        print(f"Please open this file in your browser: {filepath}")
