"""
HTML views for mc-webui
"""

import os
import time
import logging
from flask import Blueprint, render_template, request, jsonify
from app.config import config, runtime_config

logger = logging.getLogger(__name__)

views_bp = Blueprint('views', __name__)

# Thresholds for the strict health check (used by the external watchdog).
# Kept as module constants so they can be tuned without code review.
HEALTH_STRICT_MAX_RX_STALE_SEC = 300        # >5 min since last RX event → unhealthy
HEALTH_STRICT_MAX_STATS_FAILURES = 5        # ≥5 consecutive get_stats/battery failures → unhealthy


@views_bp.route('/')
def index():
    """
    Main chat view - displays message list and send form.
    """
    return render_template(
        'index.html',
        device_name=runtime_config.get_device_name()
    )


@views_bp.route('/dm')
def direct_messages():
    """
    Direct Messages view - full-page DM interface.

    Query params:
        conversation: Optional conversation ID to open initially
    """
    initial_conversation = request.args.get('conversation', '')

    return render_template(
        'dm.html',
        device_name=runtime_config.get_device_name(),
        initial_conversation=initial_conversation
    )


@views_bp.route('/contacts/manage')
def contact_management():
    """
    Contact Management Settings - manual approval + cleanup + navigation.
    """
    return render_template(
        'contacts-manage.html',
        device_name=runtime_config.get_device_name()
    )


@views_bp.route('/contacts/add')
def contact_add():
    """
    Add Contact page - URI paste, QR scan, manual fields.
    """
    return render_template(
        'contacts-add.html',
        device_name=runtime_config.get_device_name()
    )


@views_bp.route('/contacts/pending')
def contact_pending_list():
    """
    Full-screen pending contacts list.
    """
    return render_template(
        'contacts-pending.html',
        device_name=runtime_config.get_device_name()
    )


@views_bp.route('/contacts/existing')
def contact_existing_list():
    """
    Full-screen existing contacts list with search, filter, sort.
    """
    return render_template(
        'contacts-existing.html',
        device_name=runtime_config.get_device_name()
    )


@views_bp.route('/console')
def console():
    """
    Interactive meshcli console - chat-style command interface.

    WebSocket connection is handled by the main Flask app and proxied to bridge.
    """
    return render_template(
        'console.html',
        device_name=runtime_config.get_device_name()
    )


@views_bp.route('/logs')
def logs():
    """System log viewer - real-time log streaming with filters."""
    return render_template('logs.html')


@views_bp.route('/health')
def health():
    """Health check endpoint for monitoring.

    Returns 503 when BLE reconnection has permanently failed so Docker's
    healthcheck triggers a container restart (which clears all BLE state).
    """
    from flask import current_app
    dm = getattr(current_app, 'device_manager', None)
    if dm and getattr(dm, '_ble_permanently_failed', False):
        return 'BLE connection permanently failed', 503
    return 'OK', 200


@views_bp.route('/health/strict')
def health_strict():
    """Stricter device-health check for the external watchdog.

    Returns 503 when:
      - BLE reconnection has permanently failed (same as /health), or
      - The device is connected but has produced N consecutive stats/battery
        failures (firmware/USB stalled), or
      - The device is connected via USB and we haven't received any RX event
        in HEALTH_STRICT_MAX_RX_STALE_SEC seconds.

    The watchdog uses this to catch "sluggish" failures the regular /health
    endpoint can't see. Returns 200 otherwise. Always returns JSON so the
    caller can log the specific reason.
    """
    from flask import current_app
    dm = getattr(current_app, 'device_manager', None)
    if dm is None:
        return jsonify({'status': 'ok', 'reason': 'no_device_manager'}), 200

    if getattr(dm, '_ble_permanently_failed', False):
        return jsonify({'status': 'fail', 'reason': 'ble_permanent_failure'}), 503

    if not getattr(dm, 'is_connected', False):
        # Don't fail strict on "not yet connected" — let DM keep retrying.
        return jsonify({'status': 'ok', 'reason': 'not_connected'}), 200

    failures = getattr(dm, '_consecutive_stats_failures', 0)
    if failures >= HEALTH_STRICT_MAX_STATS_FAILURES:
        return jsonify({
            'status': 'fail',
            'reason': 'consecutive_stats_failures',
            'count': failures,
        }), 503

    transport = getattr(config, 'transport_type', 'serial')
    last_rx = getattr(dm, '_last_rx_at', 0.0) or 0.0
    if transport in ('serial', 'usb') and last_rx > 0:
        stale = time.time() - last_rx
        if stale > HEALTH_STRICT_MAX_RX_STALE_SEC:
            return jsonify({
                'status': 'fail',
                'reason': 'rx_stale',
                'seconds_since_last_rx': int(stale),
            }), 503

    return jsonify({
        'status': 'ok',
        'consecutive_stats_failures': failures,
        'seconds_since_last_rx': int(time.time() - last_rx) if last_rx else None,
    }), 200
