#!/bin/bash
# montemusic local helper installer — run once per Mac (double-click this file).
# Installs a small local-only server on 127.0.0.1:8766 that lets the
# montemusic.pages.dev Play button open audio in mpv on THIS Mac.
#
# Safari (as of macOS 26) blocks fetch() from an HTTPS page to plain
# http://localhost — the loopback mixed-content exemption isn't enough
# there. So this server speaks HTTPS too, using a certificate generated
# by mkcert and trusted in this Mac's own login keychain (no sudo/admin
# password needed — that's specifically a login-keychain trust, not a
# system-wide one).
set -e

INSTALL_DIR="$HOME/.local/share/montemusic-vlc-helper"
mkdir -p "$INSTALL_DIR"

echo "Εγκατάσταση montemusic helper σε $INSTALL_DIR ..."

if ! command -v python3 >/dev/null 2>&1; then
  echo "Δεν βρέθηκε python3. Εγκατέστησε τα Xcode Command Line Tools (xcode-select --install) και ξανατρέξε αυτό το script."
  read -p "Πάτα Enter για κλείσιμο..."
  exit 1
fi

if ! command -v mpv >/dev/null 2>&1; then
  echo "Το mpv δεν βρέθηκε."
  if command -v brew >/dev/null 2>&1; then
    echo "Εγκατάσταση mpv μέσω Homebrew..."
    brew install mpv
  else
    echo "Δεν βρέθηκε Homebrew. Εγκατέστησε το mpv χειροκίνητα (https://mpv.io/installation/) και ξανατρέξε αυτό το script."
    read -p "Πάτα Enter για κλείσιμο..."
    exit 1
  fi
fi

if ! command -v yt-dlp >/dev/null 2>&1; then
  echo "Το yt-dlp δεν βρέθηκε (χρειάζεται για το κουμπί ανανέωσης YouTube cookies)."
  if command -v brew >/dev/null 2>&1; then
    echo "Εγκατάσταση yt-dlp μέσω Homebrew..."
    brew install yt-dlp
  else
    echo "Δεν βρέθηκε Homebrew. Εγκατέστησε το yt-dlp χειροκίνητα (https://github.com/yt-dlp/yt-dlp#installation) και ξανατρέξε αυτό το script."
    read -p "Πάτα Enter για κλείσιμο..."
    exit 1
  fi
fi

if ! command -v mkcert >/dev/null 2>&1; then
  echo "Το mkcert δεν βρέθηκε (χρειάζεται για το τοπικό certificate)."
  if command -v brew >/dev/null 2>&1; then
    echo "Εγκατάσταση mkcert μέσω Homebrew..."
    brew install mkcert
  else
    echo "Δεν βρέθηκε Homebrew. Εγκατέστησε πρώτα Homebrew (https://brew.sh) και ξανατρέξε αυτό το script."
    read -p "Πάτα Enter για κλείσιμο..."
    exit 1
  fi
fi

if [ ! -f "$INSTALL_DIR/cert.pem" ]; then
  echo "Δημιουργία τοπικού certificate..."
  mkcert -cert-file "$INSTALL_DIR/cert.pem" -key-file "$INSTALL_DIR/key.pem" localhost 127.0.0.1 ::1
  CAROOT=$(mkcert -CAROOT)
  security add-trusted-cert -r trustRoot -k "$HOME/Library/Keychains/login.keychain-db" "$CAROOT/rootCA.pem"
  echo "Το certificate εμπιστεύεται πλέον σε αυτό το Mac (login keychain, χωρίς sudo)."
fi

cat > "$INSTALL_DIR/vlc_helper.py" <<'PYEOF'
#!/usr/bin/env python3
"""Local-only mpv helper for montemusic.pages.dev.
Binds to 127.0.0.1 (loopback) over HTTPS, using a certificate this Mac's
own login keychain trusts (mkcert) — plain HTTP to localhost isn't
enough for Safari's fetch() from an HTTPS page.
mpv handles YouTube links natively (built-in yt-dlp support), so no
separate resolve step is needed here.

Also exposes /renew-cookies: re-exports fresh YouTube cookies from this
Mac's Chrome and pushes them straight to the montemusic-resolver Render
service via the Render API, then triggers a redeploy — this is what
fixes VLC-on-iPhone when it starts failing with a YouTube bot-check
error. Needs a Render API key at
~/Library/Mobile Documents/com~apple~CloudDocs/Sites/montemusic/monte-helper/render_api_key.txt
(iCloud-synced, kept out of the public site deploy via .pagesignore).
"""
import json
import os
import ssl
import subprocess
import time
import urllib.request
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlparse, parse_qs

PORT = 8766
ALLOWED_ORIGIN = "https://montemusic.pages.dev"
HERE = os.path.dirname(os.path.abspath(__file__))
CERT_FILE = os.path.join(HERE, "cert.pem")
KEY_FILE = os.path.join(HERE, "key.pem")

RENDER_SERVICE_ID = "srv-da26jejutv3s73bkfd30"
RENDER_API_KEY_FILE = os.path.expanduser(
    "~/Library/Mobile Documents/com~apple~CloudDocs/Sites/montemusic/monte-helper/render_api_key.txt"
)
COOKIES_SECRET_NAME = "youtube_cookies.txt"


def _filter_cookies(raw_text):
    kept = []
    for line in raw_text.splitlines(keepends=True):
        stripped = line.strip()
        if not stripped or stripped.startswith("#"):
            kept.append(line)
            continue
        domain = stripped.split("\t")[0].lstrip(".").lower()
        if "google" in domain or "youtube" in domain:
            kept.append(line)
    return "".join(kept)


def _render_api_request(path, payload):
    with open(RENDER_API_KEY_FILE) as f:
        api_key = f.read().strip()
    req = urllib.request.Request(
        f"https://api.render.com/v1/services/{RENDER_SERVICE_ID}{path}",
        data=json.dumps(payload).encode("utf-8"),
        method="PUT" if "secret-files" in path else "POST",
        headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
    )
    with urllib.request.urlopen(req, timeout=30) as resp:
        if resp.status not in (200, 201):
            raise RuntimeError(f"Render API {path} returned {resp.status}")


def renew_youtube_cookies():
    subprocess.run(["osascript", "-e", 'quit app "Google Chrome"'],
                    stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    time.sleep(2)

    export_path = "/tmp/montemusic_cookies_export.txt"
    result = subprocess.run(
        ["yt-dlp", "--cookies-from-browser", "chrome", "--cookies", export_path,
         "--skip-download", "--simulate", "https://www.youtube.com/watch?v=dQw4w9WgXcQ"],
        capture_output=True, text=True, timeout=60,
    )
    if result.returncode != 0:
        raise RuntimeError(result.stderr.strip() or "yt-dlp export failed")

    with open(export_path) as f:
        filtered = _filter_cookies(f.read())
    os.remove(export_path)

    _render_api_request(f"/secret-files/{COOKIES_SECRET_NAME}", {"content": filtered})
    _render_api_request("/deploys", {"clearCache": "do_not_clear"})


class Handler(BaseHTTPRequestHandler):
    def log_message(self, fmt, *args):
        print("%s - %s" % (self.address_string(), fmt % args))

    def _send_json(self, status, payload):
        body = json.dumps(payload).encode("utf-8")
        self.send_response(status)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(body)))
        self.send_header("Access-Control-Allow-Origin", ALLOWED_ORIGIN)
        self.send_header("Access-Control-Allow-Private-Network", "true")
        self.end_headers()
        self.wfile.write(body)

    def do_OPTIONS(self):
        self.send_response(204)
        self.send_header("Access-Control-Allow-Origin", ALLOWED_ORIGIN)
        self.send_header("Access-Control-Allow-Methods", "GET, OPTIONS")
        self.send_header("Access-Control-Allow-Headers", "*")
        self.send_header("Access-Control-Allow-Private-Network", "true")
        self.end_headers()

    def do_GET(self):
        parsed = urlparse(self.path)
        params = parse_qs(parsed.query)

        if parsed.path == "/mpv":
            youtube_url = params.get("url", [None])[0]
            if not youtube_url:
                return self._send_json(400, {"ok": False, "error": "missing url param"})
            try:
                subprocess.Popen(
                    ["mpv", youtube_url],
                    stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
                    stdin=subprocess.DEVNULL, start_new_session=True,
                )
                print("Opened in mpv:", youtube_url)
                return self._send_json(200, {"ok": True})
            except Exception as e:
                print("mpv launch failed:", e)
                return self._send_json(500, {"ok": False, "error": str(e)})

        if parsed.path == "/renew-cookies":
            try:
                renew_youtube_cookies()
                print("YouTube cookies renewed, resolver redeploy triggered")
                return self._send_json(200, {"ok": True})
            except Exception as e:
                print("renew-cookies failed:", e)
                return self._send_json(500, {"ok": False, "error": str(e)})

        if parsed.path == "/health":
            return self._send_json(200, {"ok": True})

        self._send_json(404, {"ok": False, "error": "not found"})


if __name__ == "__main__":
    server = HTTPServer(("127.0.0.1", PORT), Handler)
    ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    ctx.load_cert_chain(certfile=CERT_FILE, keyfile=KEY_FILE)
    server.socket = ctx.wrap_socket(server.socket, server_side=True)
    print(f"montemusic helper listening on https://127.0.0.1:{PORT}")
    server.serve_forever()
PYEOF

PLIST="$HOME/Library/LaunchAgents/com.montemusic.vlchelper.plist"
cat > "$PLIST" <<PLISTEOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.montemusic.vlchelper</string>
    <key>ProgramArguments</key>
    <array>
        <string>$(command -v python3)</string>
        <string>$INSTALL_DIR/vlc_helper.py</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
    </dict>
    <key>StandardOutPath</key>
    <string>$INSTALL_DIR/vlc_helper.log</string>
    <key>StandardErrorPath</key>
    <string>$INSTALL_DIR/vlc_helper.log</string>
</dict>
</plist>
PLISTEOF

launchctl unload "$PLIST" >/dev/null 2>&1 || true
launchctl load -w "$PLIST"

sleep 1
if curl -sk -m 3 https://127.0.0.1:8766/health | grep -q '"ok": true'; then
  echo ""
  echo "✅ Έτοιμο! Το κουμπί Play στο https://montemusic.pages.dev θα δουλεύει τώρα σε αυτό το Mac."
else
  echo ""
  echo "⚠️  Κάτι πήγε στραβά. Έλεγξε το log: $INSTALL_DIR/vlc_helper.log"
fi

read -p "Πάτα Enter για κλείσιμο..."
