from microdot import Microdot, send_file
from microdot.session import with_session
from models.tab import Tab
from models.profile import Profile
import json
import os
import time

controller = Microdot()
tabs = Tab()
profiles = Profile()

def get_current_profile_id(session=None):
    """Get the current active profile ID from session or fallback to first."""
    profile_list = profiles.list()
    session_profile = None
    if session is not None:
        session_profile = session.get('current_profile')
    if session_profile and session_profile in profile_list:
        return session_profile
    if profile_list:
        return profile_list[0]
    return None

def get_profile_tab_order(profile_id):
    """Get the tab order for a profile."""
    if not profile_id:
        return []
    profile = profiles.read(profile_id)
    if profile:
        # Support both "tab_order" (old) and "tabs" (new) format
        return profile.get("tabs", profile.get("tab_order", []))
    return []

def get_current_tab_id(request, session=None):
    """Get the current tab ID from cookie."""
    # Read from cookie first
    current_tab = request.cookies.get('current_tab')
    if current_tab:
        return current_tab
    
    # Fallback to first tab in current profile
    profile_id = get_current_profile_id(session)
    if profile_id:
        profile = profiles.read(profile_id)
        if profile:
            # Support both "tabs" (new) and "tab_order" (old) format
            tabs_list = profile.get("tabs", profile.get("tab_order", []))
            if tabs_list:
                return tabs_list[0]
    return None

def _render_tabs_list_fragment(request, session):
    """Helper function to render tabs list HTML fragment."""
    profile_id = get_current_profile_id(session)
    # #region agent log
    try:
        os.makedirs('/home/pi/led-controller/.cursor', exist_ok=True)
        with open('/home/pi/led-controller/.cursor/debug.log', 'a') as _log:
            _log.write(json.dumps({
                "sessionId": "debug-session",
                "runId": "tabs-pre-fix",
                "hypothesisId": "H1",
                "location": "src/controllers/tab.py:_render_tabs_list_fragment",
                "message": "tabs list fragment",
                "data": {
                    "profile_id": profile_id,
                    "profile_count": len(profiles.list())
                },
                "timestamp": int(time.time() * 1000)
            }) + "\n")
    except Exception:
        pass
    # #endregion
    if not profile_id:
        return '<div class="tabs-list">No profile selected</div>', 200, {'Content-Type': 'text/html'}
    
    tab_order = get_profile_tab_order(profile_id)
    current_tab_id = get_current_tab_id(request, session)
    
    html = '<div class="tabs-list">'
    for tab_id in tab_order:
        tab_data = tabs.read(tab_id)
        if tab_data:
            active_class = 'active' if str(tab_id) == str(current_tab_id) else ''
            tab_name = tab_data.get('name', 'Tab ' + str(tab_id))
            html += (
                '<button class="tab-button ' + active_class + '" '
                'hx-get="/tabs/' + str(tab_id) + '/content-fragment" '
                'hx-target="#tab-content" '
                'hx-swap="innerHTML" '
                'hx-push-url="true" '
                'hx-trigger="click" '
                'onclick="document.querySelectorAll(\'.tab-button\').forEach(b => b.classList.remove(\'active\')); this.classList.add(\'active\');">'
                + tab_name +
                '</button>'
            )
    html += '</div>'
    return html, 200, {'Content-Type': 'text/html'}

def _render_tab_content_fragment(request, session, id):
    """Helper function to render tab content HTML fragment."""
    # Handle 'current' as a special case
    if id == 'current':
        current_tab_id = get_current_tab_id(request, session)
        if not current_tab_id:
            accept_header = request.headers.get('Accept', '')
            wants_html = 'text/html' in accept_header
            if wants_html:
                return '<div class="error">No current tab set</div>', 404, {'Content-Type': 'text/html'}
            return json.dumps({"error": "No current tab set"}), 404
        id = current_tab_id
    
    tab = tabs.read(id)
    if not tab:
        return '<div>Tab not found</div>', 404, {'Content-Type': 'text/html'}
    
    # Set this tab as the current tab in session
    session['current_tab'] = str(id)
    session.save()

    # If this is a direct page load (not HTMX), return full UI so CSS loads.
    if not request.headers.get('HX-Request'):
        return send_file('templates/index.html')
    
    tab_name = tab.get('name', 'Tab ' + str(id))
    
    html = (
        '<div class="presets-section" data-tab-id="' + str(id) + '">'
        '<h3>Presets</h3>'
        '<div class="profiles-actions" style="margin-bottom: 1rem;"></div>'
        '<div id="presets-list-tab" class="presets-list">'
        '<!-- Presets will be loaded here -->'
        '</div>'
        '</div>'
    )
    return html, 200, {'Content-Type': 'text/html'}

@controller.get('')
@with_session
async def list_tabs(request, session):
    """List all tabs with current tab info."""
    profile_id = get_current_profile_id(session)
    current_tab_id = get_current_tab_id(request, session)
    
    # Get tab order for current profile
    tab_order = get_profile_tab_order(profile_id) if profile_id else []
    
    # Build tabs list with metadata
    tabs_data = {}
    for tab_id in tabs.list():
        tab_data = tabs.read(tab_id)
        if tab_data:
            tabs_data[tab_id] = tab_data
    
    return json.dumps({
        "tabs": tabs_data,
        "tab_order": tab_order,
        "current_tab_id": current_tab_id,
        "profile_id": profile_id
    }), 200, {'Content-Type': 'application/json'}

# Get current tab - returns JSON with tab data and content info
@controller.get('/current')
@with_session
async def get_current_tab(request, session):
    """Get the current tab from session."""
    current_tab_id = get_current_tab_id(request, session)
    if not current_tab_id:
        return json.dumps({"error": "No current tab set", "tab": None, "tab_id": None}), 404
    
    tab = tabs.read(current_tab_id)
    if tab:
        return json.dumps({
            "tab": tab,
            "tab_id": current_tab_id
        }), 200, {'Content-Type': 'application/json'}
    return json.dumps({"error": "Tab not found", "tab": None, "tab_id": None}), 404

@controller.post('/<id>/set-current')
async def set_current_tab(request, id):
    """Set a tab as the current tab in cookie."""
    tab = tabs.read(id)
    if not tab:
        return json.dumps({"error": "Tab not found"}), 404
    
    # Set cookie with current tab
    response_data = json.dumps({"message": "Current tab set", "tab_id": id})
    response = response_data, 200, {
        'Content-Type': 'application/json',
        'Set-Cookie': f'current_tab={id}; Path=/; Max-Age=31536000'  # 1 year expiry
    }
    return response

@controller.get('/<id>')
async def get_tab(request, id):
    """Get a specific tab by ID."""
    tab = tabs.read(id)
    if tab:
        return json.dumps(tab), 200, {'Content-Type': 'application/json'}
    return json.dumps({"error": "Tab not found"}), 404

@controller.put('/<id>')
async def update_tab(request, id):
    """Update an existing tab."""
    try:
        data = request.json
        if tabs.update(id, data):
            return json.dumps(tabs.read(id)), 200, {'Content-Type': 'application/json'}
        return json.dumps({"error": "Tab not found"}), 404
    except Exception as e:
        return json.dumps({"error": str(e)}), 400

@controller.delete('/<id>')
@with_session
async def delete_tab(request, session, id):
    """Delete a tab."""
    try:
        # Handle 'current' tab ID
        if id == 'current':
            current_tab_id = get_current_tab_id(request, session)
            if current_tab_id:
                id = current_tab_id
            else:
                return json.dumps({"error": "No current tab to delete"}), 404
        
        if tabs.delete(id):
            # Remove from profile's tabs
            profile_id = get_current_profile_id(session)
            if profile_id:
                profile = profiles.read(profile_id)
                if profile:
                    # Support both "tabs" (new) and "tab_order" (old) format
                    tabs_list = profile.get('tabs', profile.get('tab_order', []))
                    if id in tabs_list:
                        tabs_list.remove(id)
                        profile['tabs'] = tabs_list
                        # Remove old tab_order if it exists
                        if 'tab_order' in profile:
                            del profile['tab_order']
                        profiles.update(profile_id, profile)
            
            # Clear cookie if the deleted tab was the current tab
            current_tab_id = get_current_tab_id(request, session)
            if current_tab_id == id:
                response_data = json.dumps({"message": "Tab deleted successfully"})
                response = response_data, 200, {
                    'Content-Type': 'application/json',
                    'Set-Cookie': 'current_tab=; Path=/; Max-Age=0'  # Clear cookie
                }
                return response
            
            return json.dumps({"message": "Tab deleted successfully"}), 200, {'Content-Type': 'application/json'}
        
        return json.dumps({"error": "Tab not found"}), 404
    except Exception as e:
        import sys
        try:
            sys.print_exception(e)
        except:
            pass
        return json.dumps({"error": str(e)}), 500, {'Content-Type': 'application/json'}

@controller.post('')
@with_session
async def create_tab(request, session):
    """Create a new tab."""
    try:
        # Handle form data or JSON
        if request.form:
            name = request.form.get('name', '').strip()
            ids_str = request.form.get('ids', '1').strip()
            names = [id.strip() for id in ids_str.split(',') if id.strip()]
            preset_ids = None
        else:
            data = request.json or {}
            name = data.get("name", "")
            names = data.get("names", None)
            preset_ids = data.get("presets", None)
        
        if not name:
            return json.dumps({"error": "Tab name cannot be empty"}), 400
        
        tab_id = tabs.create(name, names, preset_ids)
        
        # Add to current profile's tabs
        profile_id = get_current_profile_id(session)
        if profile_id:
            profile = profiles.read(profile_id)
            if profile:
                # Support both "tabs" (new) and "tab_order" (old) format
                tabs_list = profile.get('tabs', profile.get('tab_order', []))
                if tab_id not in tabs_list:
                    tabs_list.append(tab_id)
                    profile['tabs'] = tabs_list
                    # Remove old tab_order if it exists
                    if 'tab_order' in profile:
                        del profile['tab_order']
                    profiles.update(profile_id, profile)
        
        # Return JSON response with tab ID
        tab_data = tabs.read(tab_id)
        return json.dumps({tab_id: tab_data}), 201, {'Content-Type': 'application/json'}
    except Exception as e:
        import sys
        sys.print_exception(e)
        return json.dumps({"error": str(e)}), 400

@controller.post('/<id>/clone')
@with_session
async def clone_tab(request, session, id):
    """Clone an existing tab and add it to the current profile."""
    try:
        source = tabs.read(id)
        if not source:
            return json.dumps({"error": "Tab not found"}), 404

        data = request.json or {}
        source_name = source.get("name") or f"Tab {id}"
        new_name = data.get("name") or f"{source_name} Copy"
        clone_id = tabs.create(new_name, source.get("names"), source.get("presets"))
        extra = {k: v for k, v in source.items() if k not in ("name", "names", "presets")}
        if extra:
            tabs.update(clone_id, extra)

        profile_id = get_current_profile_id(session)
        if profile_id:
            profile = profiles.read(profile_id)
            if profile:
                tabs_list = profile.get('tabs', profile.get('tab_order', []))
                if clone_id not in tabs_list:
                    tabs_list.append(clone_id)
                    profile['tabs'] = tabs_list
                    if 'tab_order' in profile:
                        del profile['tab_order']
                    profiles.update(profile_id, profile)

        tab_data = tabs.read(clone_id)
        return json.dumps({clone_id: tab_data}), 201, {'Content-Type': 'application/json'}
    except Exception as e:
        import sys
        try:
            sys.print_exception(e)
        except:
            pass
        return json.dumps({"error": str(e)}), 400
