import os
import json
import sys
import requests
from flask import Flask, jsonify, render_template, request, session
from datetime import datetime, timedelta

# Reconfigure stdout/stderr to use UTF-8 if supported
try:
    if hasattr(sys.stdout, 'reconfigure'):
        sys.stdout.reconfigure(encoding='utf-8')
    if hasattr(sys.stderr, 'reconfigure'):
        sys.stderr.reconfigure(encoding='utf-8')
except Exception:
    pass

def safe_print(msg):
    timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    full_msg = f"[{timestamp}] {msg}"
    try:
        print(full_msg, flush=True)
    except UnicodeEncodeError:
        try:
            print(full_msg.encode('ascii', errors='backslashreplace').decode('ascii'), flush=True)
        except Exception:
            pass

# Paths & Settings
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
CACHE_FILE = os.path.join(BASE_DIR, 'token_cache.json')

# Load environment variables manually
def load_env():
    env_path = os.path.join(BASE_DIR, '.env')
    if os.path.exists(env_path):
        try:
            with open(env_path, 'r') as f:
                for line in f:
                    line = line.strip()
                    if line and not line.startswith('#') and '=' in line:
                        key, val = line.split('=', 1)
                        os.environ[key.strip()] = val.strip()
        except Exception as e:
            safe_print(f"[!] Warning: failed to load .env: {e}")

load_env()

app = Flask(__name__, static_folder='static', template_folder='templates')
application = app
app.secret_key = os.getenv("FLASK_SECRET_KEY", os.urandom(24).hex())
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=30)

BASE_URL = "https://usmart.if.ua"
USERNAME = os.getenv("USMARTIVE_USERNAME", "z.lyubomyr@gmail.com")
PASSWORD = os.getenv("USMARTIVE_PASSWORD", "47135471")

# Mimic the Android Retrofit/OkHttp Client signature
HEADERS_TEMPLATE = {
    "User-Agent": "okhttp/4.9.2",
    "Content-Type": "application/json"
}

# Gate configuration mappings
GATES = {
    1: {
        "name": "Тайстра ворота",
        "device_name": "Comfort Park_Тайстра",
        "device_id": "f1885c14-6084-4290-87b6-ec12e9185a43",
        "button_id": "5477c27d-91ae-437a-b9e5-1f733fa249f2"
    },
    2: {
        "name": "Епіцентр ворота",
        "device_name": "Comfort Park Центральні ворота",
        "device_id": "38a92349-e2f4-4ac1-bb6c-2a6b8987190a",
        "button_id": "a66a3cca-50b5-46ea-8104-1032f341e3a1"
    },
    3: {
        "name": "Тайстра хвіртка",
        "device_name": "Comfort Park_Тайстра",
        "device_id": "f1885c14-6084-4290-87b6-ec12e9185a43",
        "button_id": "cbe6f3e6-0958-417f-889c-75b6e20e19d5"
    },
    4: {
        "name": "14 хвіртка",
        "device_name": "Comfort Park 14",
        "device_id": "5ba9b536-dd56-4d0f-8ef0-d29d4039dd0a",
        "button_id": "2c324443-0846-4073-8186-faa29f902d4c"
    },
    5: {
        "name": "13 Хвіртка",
        "device_name": "Comfort Park Simi",
        "device_id": "235c5ca6-92e8-4e38-9a41-dc351bb99a38",
        "button_id": "951a16ba-d4ea-46bd-85dc-cc68cabae5e5"
    },
    6: {
        "name": "13 Ворота",
        "device_name": "Comfort Park Simi",
        "device_id": "235c5ca6-92e8-4e38-9a41-dc351bb99a38",
        "button_id": "dc5757f2-8e90-4207-ad9c-dd2979fff54d"
    },
    7: {
        "name": "Епіцентр хвіртка",
        "device_name": "Comfort Park Центральні ворота",
        "device_id": "38a92349-e2f4-4ac1-bb6c-2a6b8987190a",
        "button_id": "ef15ea5b-d595-43f1-a9b6-999e6d785761"
    }
}

def load_cached_token():
    """
    Loads token from the local cache file.
    """
    if os.path.exists(CACHE_FILE):
        try:
            with open(CACHE_FILE, 'r') as f:
                data = json.load(f)
                return data.get('token')
        except Exception:
            pass
    return None

def save_token_to_cache(token):
    """
    Saves the token to the local cache file.
    """
    try:
        with open(CACHE_FILE, 'w') as f:
            json.dump({'token': token}, f)
    except Exception as e:
        safe_print(f"[!] Warning: failed to save token cache: {e}")

def perform_login():
    """
    Logs in to retrieve a new token and caches it.
    """
    login_url = f"{BASE_URL}/auth/user/login"
    payload = {"username": USERNAME, "password": PASSWORD}
    
    safe_print("[*] Performing authentication request...")
    r = requests.post(login_url, json=payload, headers=HEADERS_TEMPLATE, timeout=10)
    
    if r.status_code == 200:
        token = r.json().get("token")
        if token:
            save_token_to_cache(token)
            return token
    safe_print(f"[!] Login failed. Status: {r.status_code}")
    return None

def trigger_gate_open(token, gate_config):
    """
    Sends the POST request to open the gate.
    """
    device_id = gate_config["device_id"]
    button_id = gate_config["button_id"]
    url = f"{BASE_URL}/device/{device_id}/button/{button_id}/message"
    
    headers = HEADERS_TEMPLATE.copy()
    headers["Authorization"] = f"Bearer {token}"
    
    payload = {
        "did": device_id,
        "type": 0,
        "data": 0
    }
    
    safe_print(f"[*] Sending open request to {gate_config['name']}...")
    r = requests.post(url, json=payload, headers=headers, timeout=10)
    return r

@app.route('/sw.js')
def serve_sw():
    return app.send_static_file('sw.js')

@app.route('/manifest.json')
def serve_manifest():
    return app.send_static_file('manifest.json')

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/api/open/<int:gate_id>', methods=['POST'])
def open_gate(gate_id):
    gate_config = GATES.get(gate_id)
    if not gate_config:
        return jsonify({"error": "Invalid gate ID"}), 400
        
    token = load_cached_token()
    
    # If no token cached, login first
    if not token:
        token = perform_login()
        if not token:
            return jsonify({"error": "Failed to authenticate with the server"}), 401
            
    # Try sending request
    response = trigger_gate_open(token, gate_config)
    
    # If token expired (401), perform login and retry once
    if response.status_code == 401:
        safe_print("[!] Token rejected (401). Refreshing token...")
        token = perform_login()
        if not token:
            return jsonify({"error": "Failed to refresh token after 401"}), 401
            
        # Retry request
        response = trigger_gate_open(token, gate_config)
        
    if response.status_code in [200, 204]:
        return jsonify({"success": True, "message": f"{gate_config['name']} opened successfully."})
    else:
        return jsonify({"error": f"Server error: {response.status_code}"}), 500

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=5001, debug=True)
