from flask import Flask, request, jsonify, abort
import requests
import os
import xml.etree.ElementTree as ET
import time

app = Flask(__name__)

# Optional token for access control (not production secure)
HEALTH_TOKEN = os.environ.get('HEALTH_TOKEN')

@app.route('/healthcheck')
def healthcheck():
    token = request.args.get('token') or request.headers.get('X-Health-Token')
    if HEALTH_TOKEN and token != HEALTH_TOKEN:
        return jsonify({'error': 'Unauthorized'}), 401

    # New behavior: prefer service id lookup
    service_id = request.args.get('id')
    host = request.args.get('host')
    port = request.args.get('port')
    proto = request.args.get('proto', 'http')

    if service_id:
        # Load services.xml and find service by id
        try:
            tree = ET.parse('/usr/share/nginx/html/services.xml')
            root = tree.getroot()
        except Exception as e:
            return jsonify({'error': 'unable to parse services.xml', 'detail': str(e)}), 500

        # Find service element by id
        svc = None
        for s in root.findall('.//service'):
            sid = s.get('id') or s.get('name')
            if sid and sid == service_id:
                svc = s
                break
        if svc is None:
            return jsonify({'error': 'service id not found'}), 404

        # Determine host/port/proto preference: local-ip > tailscale-ip root > host attr > fallback to provided host
        local_ip = svc.get('local-ip')
        root_tailscale = root.get('tailscale-ip')
        host_attr = svc.get('host')
        proto_attr = svc.get('proto') or proto
        port_attr = svc.get('port') or port
        health_path = svc.get('health-path', '')  # Custom health check path (e.g., /api/health, /ping)

        # prefer local-ip if present
        target_host = local_ip or root_tailscale or (host_attr.split(':')[0] if host_attr and ':' in host_attr else None) or host
        target_port = port_attr or (host_attr.split(':')[1] if host_attr and ':' in host_attr else None)
        target_proto = proto_attr
        if not target_host or not target_port:
            return jsonify({'error': 'service missing host or port mapping'}), 400

        host = target_host
        port = target_port
        proto = target_proto

    if not host or not port:
        return jsonify({'error': 'missing parameters, expected host and port or id'}), 400

    # Build URL with optional custom health path
    health_path = health_path if 'health_path' in locals() else ''
    url = f"{proto}://{host}:{port}{health_path}"

    try:
        # Use HEAD to do a lightweight check
        r = requests.head(url, timeout=4, allow_redirects=True, verify=False)
        # Any 2xx/3xx is considered OK
        ok = 200 <= r.status_code < 400
        return jsonify({'ok': ok, 'status_code': r.status_code}), (200 if ok else 502)
    except requests.RequestException as e:
        return jsonify({'ok': False, 'error': str(e)}), 502

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8081)
