#!/usr/bin/env python3
import cgi, sys
sys.path.insert(0, '/opt/ngon/apps')
from managers.auth_manager import AuthManager, generate_login_page_html

_form = cgi.FieldStorage()
_auth = AuthManager('inventory')
_auth_required, _should_exit, _headers = _auth.require_auth(_form)

if _should_exit:
    print("Content-Type: application/json")
    if _headers:
        print(_headers)
    print("")
    if _auth_required:
        print('{"success": false, "error": "Authentication required"}')
    else:
        print('{"success": true}')
    sys.exit(0)

if _auth_required:
    print("Content-Type: text/html")
    print("")
    print(generate_login_page_html("Inventory"))
    sys.exit(0)


"""
Inventory Display Page
File: /var/www/html/ngon/inventory/index.py

This script displays inventory data with a three-column layout:
- Left: All miners from inventory
- Middle: Container filters (Site Pod combinations)
- Right: Floaters (placeholder for unassigned miners)
"""

import pandas as pd
import json
import csv
import os
import sys
from html import escape

# Import universal navigation
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from links import generate_dropdown_html, generate_dropdown_css, generate_dropdown_js

class InventoryManager:
    """Handles loading and processing of inventory data."""
    def __init__(self):
        self.inventory_data = []
        self.containers = set()
        self.load_data()

    def load_data(self):
        """Loads inventory data from CSV file."""
        try:
            inventory_file = '/opt/ngon/data/live/miner_inventory.csv'
            
            if os.path.exists(inventory_file):
                df = pd.read_csv(inventory_file)
                
                # Process each row
                for _, row in df.iterrows():
                    position = str(row['Position']).strip()
                    serial = str(row['Serial']).strip()
                    mac = str(row['MAC']).strip()
                    site = str(row['Site']).strip()
                    pod = str(row['Pod']).strip()
                    
                    # Skip rows with empty essential data
                    if position == 'nan' or position == '':
                        continue
                        
                    container = f"{site} {pod}"
                    self.containers.add(container)
                    
                    is_empty = (serial == 'nan' or serial == '') and (mac == 'nan' or mac == '')
                    
                    self.inventory_data.append({
                        'position': position,
                        'serial': serial if serial != 'nan' else 'Unknown',
                        'mac': mac if mac != 'nan' else 'Unknown',
                        'site': site,
                        'pod': pod,
                        'container': container,
                        'is_empty': is_empty
                    })
                    
        except Exception:
            # Fail silently if file is missing or corrupt
            pass

    def get_containers(self):
        """Returns sorted list of containers."""
        return sorted(list(self.containers))

    def get_miners_by_container(self, container):
        """Returns miners for a specific container."""
        return [miner for miner in self.inventory_data if miner['container'] == container]
    
    def get_installed_miners_count(self):
        """Returns count of installed miners (higher of MAC or Serial counts)."""
        mac_count = 0
        serial_count = 0
        
        for miner in self.inventory_data:
            # Count valid MACs (not 'Unknown', 'nan', or empty)
            if miner['mac'] not in ['Unknown', 'nan', '']:
                mac_count += 1
            
            # Count valid Serials (not 'Unknown', 'nan', or empty) 
            if miner['serial'] not in ['Unknown', 'nan', '']:
                serial_count += 1
        
        # Return the higher of the two counts
        return max(mac_count, serial_count)

def generate_html_content(inventory_manager):
    """Generates the dynamic HTML sections for the page."""
    
    # Generate miners HTML (left column)
    miners_html = []
    if not inventory_manager.inventory_data:
        miners_html.append('<div class="no-miners">No inventory data found</div>')
    else:
        for miner in inventory_manager.inventory_data:
            position = escape(miner['position'])
            serial = escape(miner['serial'])
            mac = escape(miner['mac'])
            site = escape(miner['site'])
            pod = escape(miner['pod'])
            container = escape(miner['container'])
            
            is_empty_attr = 'true' if miner.get('is_empty', False) else 'false'
            
            miners_html.append(f"""
                <div class="miner-item" data-container="{container}" data-empty="{is_empty_attr}">
                    <div class="miner-info">
                        <div class="miner-position">{position}</div>
                        <div class="miner-details">
                            <div class="miner-mac">{mac}</div>
                            <div class="miner-serial">Serial: {serial}</div>
                            <div class="miner-location">{site} Pod {pod}</div>
                        </div>
                    </div>
                </div>
            """)

    # Generate container filters HTML (middle column)
    containers = inventory_manager.get_containers()
    container_filters_html = []
    
    for container in containers:
        container_safe = escape(container, quote=True)
        miner_count = len(inventory_manager.get_miners_by_container(container))
        
        container_filters_html.append(f"""
            <div class="container-filter-item selected" data-container="{container_safe}">
                <label style="display: flex; align-items: center; cursor: pointer; width: 100%;">
                    <input type="checkbox" class="checkbox" checked>
                    <span class="container-name">{escape(container)}</span>
                </label>
                <span class="container-count">{miner_count}</span>
            </div>
        """)

    return ''.join(miners_html), ''.join(container_filters_html)

def load_miner_moves():
    """Load put and pull CSV data for the miner moves viewer."""
    moves = {'put': [], 'pull': []}
    put_csv = '/opt/ngon/data/miner_moves/put.csv'
    pull_csv = '/opt/ngon/data/miner_moves/pull.csv'

    for move_type, csv_path in [('put', put_csv), ('pull', pull_csv)]:
        try:
            if os.path.exists(csv_path):
                with open(csv_path, 'r') as f:
                    reader = csv.reader(f)
                    next(reader, None)  # Skip header
                    for row in reader:
                        if not row or not row[0] or not row[0][0].isdigit():
                            continue
                        if move_type == 'put' and len(row) >= 4:
                            moves['put'].append({
                                'date': row[0], 'serial': row[1],
                                'pod': row[2], 'position': row[3],
                                'user': row[4].strip() if len(row) > 4 else ''
                            })
                        elif move_type == 'pull' and len(row) >= 4:
                            moves['pull'].append({
                                'date': row[0], 'serial': row[1],
                                'pod': row[2], 'position': row[3],
                                'mac': row[5] if len(row) > 5 else '',
                                'user': row[6].strip() if len(row) > 6 else ''
                            })
        except Exception:
            pass

    moves['put'].reverse()
    moves['pull'].reverse()
    return moves


def render_page(inventory_manager):
    """Renders the complete HTML page."""
    miners_html, container_filters_html = generate_html_content(inventory_manager)
    all_containers_json = json.dumps(inventory_manager.get_containers())
    moves_data = load_miner_moves()
    moves_json = json.dumps(moves_data)
    put_count = len(moves_data['put'])
    pull_count = len(moves_data['pull'])

    return f"""<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Inventory Display</title>
    <style>
        * {{ margin: 0; padding: 0; box-sizing: border-box; }}
        body {{ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #1a1a1a; color: #ffffff; min-height: 100vh; padding: 20px; }}
        .container {{ max-width: none; margin: 0 auto; }}
        .header {{ background-color: rgba(255,255,255,0.05) !important; border-radius: 8px !important; padding: 30px !important; margin-bottom: 30px !important; border: 1px solid rgba(255,255,255,0.1) !important; display: flex !important; justify-content: space-between !important; align-items: flex-start !important; }}
        .header h1.dropdown-title {{ font-size: 2.2em !important; color: #00ff00 !important; margin: 0 !important; font-weight: 600 !important; }}
        .subtitle {{ color: #ccc; font-size: 1.1rem; }}
        .stats-bar {{ display: flex; gap: 20px; margin-top: 20px; flex-wrap: wrap; }}
        .stat-item {{ background-color: rgba(255,255,255,0.05); color: #ffffff; padding: 15px 25px; border-radius: 6px; font-weight: 600; border: 1px solid rgba(255,255,255,0.1); }}
        .main-content {{ display: grid; grid-template-columns: 1.8fr 0.8fr 1.4fr; gap: 15px; align-items: start; }}
        .panel {{ background-color: rgba(255,255,255,0.02); border-radius: 6px; border: 1px solid rgba(255,255,255,0.1); overflow: hidden; display: flex; flex-direction: column; height: 875px; }}
        .panel-header {{ display: flex; justify-content: space-between; align-items: center; background-color: rgba(255,255,255,0.05); color: #ffffff; padding: 15px 20px; font-size: 1.1em; font-weight: bold; border-bottom: 1px solid rgba(255,255,255,0.1); }}
        .content-area {{ padding: 15px; flex: 1; overflow-y: auto; scrollbar-width: thin; scrollbar-color: #666 transparent; }}
        
        /* Miner Item Styles */
        .miner-item {{ background-color: #222; border: 1px solid #333; border-radius: 6px; padding: 15px; margin-bottom: 8px; }}
        .miner-info {{ display: flex; justify-content: space-between; align-items: flex-start; }}
        .miner-position {{ font-weight: 600; color: #4CAF50; font-size: 1rem; margin-bottom: 8px; }}
        .miner-mac {{ font-family: 'Courier New', monospace; font-weight: 600; color: #ffffff; font-size: 0.9rem; }}
        .miner-serial {{ color: #ccc; font-size: 0.85rem; margin-top: 4px; }}
        .miner-location {{ color: #aaa; font-size: 0.8rem; margin-top: 2px; }}
        
        /* Container Filter Styles */
        .container-filter-item {{ background-color: #222; border: 1px solid #333; border-radius: 4px; padding: 12px; margin-bottom: 8px; cursor: pointer; display: flex; align-items: center; justify-content: space-between; }}
        .container-filter-item.selected {{ border-color: #555; background-color: rgba(255,255,255,0.05); }}
        .container-name {{ font-weight: 600; margin-left: 8px; }}
        .container-count {{ background-color: rgba(255,255,255,0.1); padding: 3px 8px; border-radius: 4px; font-size: 0.75rem; }}
        
        /* Search Box */
        .search-box {{ padding: 15px; border-bottom: 1px solid rgba(255,255,255,0.1); }}
        .search-input {{ width: 100%; padding: 10px 15px; border: 1px solid #333; border-radius: 4px; font-size: 0.9rem; background: #222; color: #fff; }}
        .search-input:focus {{ outline: none; border-color: #555; }}
        
        /* Filter Controls */
        .filter-controls {{ padding: 15px; border-bottom: 1px solid rgba(255,255,255,0.1); }}
        .toggle-all-btn {{ width: 100%; padding: 10px; background-color: rgba(255,255,255,0.05); color: #ffffff; border: 1px solid rgba(255,255,255,0.1); border-radius: 4px; cursor: pointer; }}
        .toggle-all-btn:hover {{ background-color: rgba(255,255,255,0.08); }}
        
        /* Empty Positions Toggle */
        .empty-positions-toggle {{ font-size: 0.8rem; font-weight: normal; display: flex; align-items: center; gap: 8px; }}
        
        /* Utility */
        .no-miners {{ text-align: center; padding: 40px 20px; color: #ccc; }}
        .hidden {{ display: none; }}
        
        /* Miner Moves Viewer */
        .moves-toggle {{ display: flex; gap: 4px; }}
        .moves-btn {{ background: rgba(255,255,255,0.05); color: #888; border: 1px solid rgba(255,255,255,0.1); border-radius: 4px; padding: 4px 12px; cursor: pointer; font-size: 0.8rem; transition: all 0.15s; }}
        .moves-btn.active {{ background: rgba(0,255,0,0.15); color: #00ff00; border-color: rgba(0,255,0,0.3); }}
        .moves-btn:hover {{ background: rgba(255,255,255,0.08); }}
        .moves-search {{ padding: 10px 15px; border-bottom: 1px solid rgba(255,255,255,0.1); }}
        .moves-table {{ width: 100%; border-collapse: collapse; font-size: 0.9rem; }}
        .moves-table th {{ text-align: left; color: #888; padding: 6px 8px; border-bottom: 1px solid rgba(255,255,255,0.15); position: sticky; top: 0; background: #1e1e1e; z-index: 1; white-space: nowrap; }}
        .moves-table td {{ padding: 5px 8px; border-bottom: 1px solid rgba(255,255,255,0.05); color: #ccc; }}
        .moves-table tr:hover td {{ background: rgba(255,255,255,0.03); }}
        .moves-table .col-serial {{ font-family: 'Courier New', monospace; font-size: 0.9rem; max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }}
        .moves-table .col-mac {{ font-family: 'Courier New', monospace; font-size: 0.9rem; white-space: nowrap; }}
        .moves-table .col-date {{ white-space: nowrap; color: #888; }}
        .moves-table .col-user {{ color: #4a9eff; font-weight: 600; }}
        .moves-count {{ font-size: 0.75rem; color: #888; padding: 8px 15px; border-bottom: 1px solid rgba(255,255,255,0.05); }}

        /* Refresh Button */
        .refresh-btn {{
            background: #22c55e;
            color: black;
            border: none;
            padding: 12px 24px;
            border-radius: 6px;
            cursor: pointer;
            font-weight: 600;
            display: flex;
            align-items: center;
            gap: 8px;
            transition: background-color 0.2s;
        }}
        .refresh-btn:hover {{
            background: #16a34a;
        }}
        .refresh-btn:disabled {{
            background: #666;
            cursor: not-allowed;
        }}
        .spinner {{
            width: 16px;
            height: 16px;
            border: 2px solid transparent;
            border-top: 2px solid currentColor;
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }}
        @keyframes spin {{
            0% {{ transform: rotate(0deg); }}
            100% {{ transform: rotate(360deg); }}
        }}

        /* Responsive */
        @media (max-width: 1400px) {{ .main-content {{ grid-template-columns: 1fr; }} }}
        
        {generate_dropdown_css()}
    </style>
</head>
<body>
<div class="header">
    <div>
        <div class="dropdown">
            <h1 class="dropdown-title">NGON Mining - Inventory</h1>
            <div class="dropdown-content">{generate_dropdown_html(AuthManager.get_user_access())}</div>
        </div>
        <p class="subtitle">View and filter mining equipment inventory</p>
        <div class="stats-bar">
            <button id="refresh-btn" onclick="refreshData()" class="refresh-btn">
                <div id="refresh-spinner" class="spinner" style="display: none;"></div>
                <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
                </svg>
                <span id="refresh-text">Refresh Data</span>
            </button>
            <div class="stat-item">Total Positions: {len(inventory_manager.inventory_data)}</div>
            <div class="stat-item">Miners in Inventory: {inventory_manager.get_installed_miners_count()}</div>
            <div class="stat-item">Containers: {len(inventory_manager.get_containers())}</div>
        </div>
    </div>
    <div></div>
</div>
<div class="container">
    <div class="main-content">
        <!-- Left Column: Miners List -->
        <div class="panel">
            <div class="panel-header">
                <span>All Miners</span>
                <div style="display: flex; align-items: center; gap: 15px;">
                    <div class="empty-positions-toggle">
                        <label for="empty-positions-filter">Only Empty Positions</label>
                        <input type="checkbox" id="empty-positions-filter">
                    </div>
                    <span id="visible-count">{len(inventory_manager.inventory_data)} items</span>
                </div>
            </div>
            <div class="content-area" id="miners-content">{miners_html}</div>
        </div>
        
        <!-- Middle Column: Search and Container Filters -->
        <div class="panel">
            <div class="panel-header"><span>Search</span></div>
            <div class="search-box">
                <input type="text" id="search-input" class="search-input" placeholder="Search MAC or Serial...">
            </div>
            <div class="panel-header"><span>Container Filters</span></div>
            <div class="filter-controls">
                <button class="toggle-all-btn" id="toggle-all">Deselect All</button>
            </div>
            <div class="content-area" id="container-filters">{container_filters_html}</div>
        </div>
        
        <!-- Right Column: Miner Moves Viewer -->
        <div class="panel">
            <div class="panel-header">
                <span>Miner Moves</span>
                <div class="moves-toggle">
                    <button class="moves-btn active" id="btn-put" onclick="switchMoves('put')">Put ({put_count})</button>
                    <button class="moves-btn" id="btn-pull" onclick="switchMoves('pull')">Pull ({pull_count})</button>
                </div>
            </div>
            <div class="moves-search">
                <input type="text" id="moves-search" class="search-input" placeholder="Search serial, pod, MAC...">
            </div>
            <div class="moves-count" id="moves-count"></div>
            <div class="content-area" id="moves-content"></div>
        </div>
    </div>
</div>

<script>
    const allContainers = new Set({all_containers_json});
    let selectedContainers = new Set(allContainers);
    let filterEmptyPositions = false;
    let searchTerm = '';
    
    function updateToggleButtonText() {{
        const button = document.getElementById('toggle-all');
        const allSelected = selectedContainers.size === allContainers.size;
        button.textContent = allSelected ? 'Deselect All' : 'Select All';
    }}
    
    function matchesSearch(miner) {{
        if (!searchTerm) return true;
        
        const mac = miner.querySelector('.miner-mac').textContent.toLowerCase();
        const serial = miner.querySelector('.miner-serial').textContent.toLowerCase();
        const searchLower = searchTerm.toLowerCase();
        
        return mac.includes(searchLower) || serial.includes(searchLower);
    }}
    
    function updateDisplay() {{
        // Update visual state of container filters
        document.querySelectorAll('.container-filter-item').forEach(item => {{
            const checkbox = item.querySelector('input[type="checkbox"]');
            const isSelected = selectedContainers.has(item.dataset.container);
            item.classList.toggle('selected', isSelected);
            checkbox.checked = isSelected;
        }});
        
        // Filter miners based on selected containers, empty positions filter, and search
        const miners = document.querySelectorAll('.miner-item');
        let visibleCount = 0;
        
        miners.forEach(miner => {{
            const minerContainer = miner.dataset.container;
            const isEmpty = miner.dataset.empty === 'true';
            
            const containerMatch = selectedContainers.has(minerContainer);
            const emptyMatch = !filterEmptyPositions || isEmpty;
            const searchMatch = matchesSearch(miner);
            
            const shouldShow = containerMatch && emptyMatch && searchMatch;
            miner.classList.toggle('hidden', !shouldShow);
            if (shouldShow) visibleCount++;
        }});
        
        // Update visible count
        document.getElementById('visible-count').textContent = `${{visibleCount}} items`;
        
        updateToggleButtonText();
    }}
    
    // Event Listeners
    document.getElementById('search-input').addEventListener('input', (e) => {{
        searchTerm = e.target.value;
        updateDisplay();
    }});
    
    document.getElementById('empty-positions-filter').addEventListener('change', (e) => {{
        filterEmptyPositions = e.target.checked;
        updateDisplay();
    }});
    
    document.getElementById('toggle-all').addEventListener('click', () => {{
        const allSelected = selectedContainers.size === allContainers.size;
        
        if (allSelected) {{
            selectedContainers.clear();
        }} else {{
            selectedContainers = new Set(allContainers);
        }}
        
        updateDisplay();
    }});
    
    document.querySelectorAll('.container-filter-item').forEach(item => {{
        item.addEventListener('click', (e) => {{
            const checkbox = item.querySelector('input[type="checkbox"]');
            if (e.target.tagName !== 'INPUT') {{
                checkbox.checked = !checkbox.checked;
            }}
            
            const container = item.dataset.container;
            if (checkbox.checked) {{
                selectedContainers.add(container);
            }} else {{
                selectedContainers.delete(container);
            }}
            
            updateDisplay();
        }});
    }});
    
    // Initialize display
    document.addEventListener('DOMContentLoaded', () => {{
        updateDisplay();
    }});
    
    // Mobile dropdown functionality
    document.addEventListener('DOMContentLoaded', function() {{
        const dropdownTitle = document.querySelector('.dropdown-title');
        const dropdownContent = document.querySelector('.dropdown-content');
        
        if (dropdownTitle && dropdownContent) {{
            dropdownTitle.addEventListener('click', function(e) {{
                if (window.innerWidth <= 768) {{
                    e.preventDefault();
                    dropdownContent.classList.toggle('show');
                }}
            }});
            
            // Close dropdown when clicking outside
            document.addEventListener('click', function(e) {{
                if (!e.target.closest('.dropdown') && dropdownContent.classList.contains('show')) {{
                    dropdownContent.classList.remove('show');
                }}
            }});
            
            // Close dropdown when window is resized to desktop
            window.addEventListener('resize', function() {{
                if (window.innerWidth > 768) {{
                    dropdownContent.classList.remove('show');
                }}
            }});
        }}
    }});
    
    // Miner Moves Viewer
    const movesData = {moves_json};
    let currentMovesType = 'put';
    let movesSearchTerm = '';

    function renderMoves() {{
        const data = movesData[currentMovesType];
        const container = document.getElementById('moves-content');
        const countEl = document.getElementById('moves-count');
        const search = movesSearchTerm.toLowerCase();

        const filtered = search ? data.filter(r =>
            r.serial.toLowerCase().includes(search) ||
            r.pod.toLowerCase().includes(search) ||
            (r.mac && r.mac.toLowerCase().includes(search)) ||
            r.user.toLowerCase().includes(search) ||
            r.position.toLowerCase().includes(search)
        ) : data;

        countEl.textContent = search
            ? `Showing ${{filtered.length}} of ${{data.length}} records`
            : `${{data.length}} records`;

        if (filtered.length === 0) {{
            container.innerHTML = '<div class="no-miners">No records found</div>';
            return;
        }}

        const isPull = currentMovesType === 'pull';
        let html = '<table class="moves-table"><thead><tr>';
        html += '<th>Date</th><th>Serial</th><th>Pod</th><th>Pos</th>';
        if (isPull) html += '<th>MAC</th>';
        html += '<th>User</th></tr></thead><tbody>';

        for (const row of filtered) {{
            html += `<tr>`;
            html += `<td class="col-date">${{row.date}}</td>`;
            html += `<td class="col-serial" title="${{row.serial}}">${{row.serial}}</td>`;
            html += `<td>${{row.pod}}</td>`;
            html += `<td>${{row.position}}</td>`;
            if (isPull) html += `<td class="col-mac">${{row.mac || ''}}</td>`;
            html += `<td class="col-user">${{row.user}}</td>`;
            html += `</tr>`;
        }}

        html += '</tbody></table>';
        container.innerHTML = html;
    }}

    function switchMoves(type) {{
        currentMovesType = type;
        document.getElementById('btn-put').classList.toggle('active', type === 'put');
        document.getElementById('btn-pull').classList.toggle('active', type === 'pull');
        document.getElementById('moves-search').value = '';
        movesSearchTerm = '';
        renderMoves();
    }}

    document.getElementById('moves-search').addEventListener('input', (e) => {{
        movesSearchTerm = e.target.value;
        renderMoves();
    }});

    renderMoves();

    function refreshData() {{
        const button = document.getElementById('refresh-btn');
        const spinner = document.getElementById('refresh-spinner');
        const buttonText = document.getElementById('refresh-text');

        button.disabled = true;
        spinner.style.display = 'block';
        buttonText.textContent = 'Refreshing...';

        fetch('./refresh_inventory.py', {{ method: 'GET' }})
        .then(response => response.json())
        .then(data => {{
            if (data.success) {{
                window.location.reload();
            }} else {{
                alert('Error refreshing data: ' + data.error);
                button.disabled = false;
                spinner.style.display = 'none';
                buttonText.textContent = 'Refresh Data';
            }}
        }})
        .catch(error => {{
            alert('Error refreshing data: ' + error);
            button.disabled = false;
            spinner.style.display = 'none';
            buttonText.textContent = 'Refresh Data';
        }});
    }}

    // Add dropdown navigation JavaScript
    {generate_dropdown_js()}
</script>
</body>
</html>"""

def main():
    """Main execution function."""
    inventory_manager = InventoryManager()
    
    # Print the HTTP header and the rendered HTML page
    print("Content-Type: text/html\n")
    print(render_page(inventory_manager))

if __name__ == "__main__":
    main()