#!/usr/bin/env python3
"""Quick web search UI for Ultimate Non-Debrid scrapers.
Usage: python3 search_web.py [port]
Then open http://localhost:8800 in a browser."""
import os, sys, json, html, re, urllib.request, urllib.parse
from http.server import HTTPServer, BaseHTTPRequestHandler

HOST = '0.0.0.0'
PORT = int(sys.argv[1]) if len(sys.argv) > 1 else 8800

# Add addon scraper to path
sys.path.insert(0, os.path.expanduser("~/addon-audit/build/ultimate-nondebrid/resources/lib"))

# ── TorrServer connection (optional) ──
TS_HOST = '127.0.0.1'
TS_PORT = 8090
TS_USER = ''
TS_PASS = ''

# ── Jackett connection (optional) ──
JACKETT_HOST = 'http://192.168.1.50'
JACKETT_PORT = '9117'
JACKETT_API = ''

def search_jackett(query, media_type='movie', season='', episode=''):
    if not JACKETT_API: return None
    q = urllib.parse.quote(query)
    if media_type == 'episode' and season and episode:
        url = f"{JACKETT_HOST}:{JACKETT_PORT}/api/v2.0/indexers/all/results/torznab/api?apikey={JACKETT_API}&t=tvsearch&q={q}&season={season}&ep={episode}"
    else:
        url = f"{JACKETT_HOST}:{JACKETT_PORT}/api/v2.0/indexers/all/results/torznab/api?apikey={JACKETT_API}&t=movie&q={q}"
    try:
        resp = urllib.request.urlopen(url, timeout=15)
        xml = resp.read().decode()
        return parse_torznab(xml)
    except: return None

def search_dmm_torznab(query, media_type='movie', season='', episode=''):
    host = 'https://zilean.elfhosted.com/torznab'
    q = urllib.parse.quote(query)
    try:
        if media_type == 'episode' and season and episode:
            url = f"{host}/tv?q={q}&season={season}&episode={episode}"
        else:
            url = f"{host}/movie?q={q}"
    except:
        url = f"{host}/movie?q={q}"
    try:
        resp = urllib.request.urlopen(url, timeout=10)
        return parse_torznab(resp.read().decode())
    except: return None

def parse_torznab(xml_text):
    results = []
    import xml.etree.ElementTree as ET
    NS = {'t': 'http://torznab.com/schemas/2015/feed'}
    try:
        root = ET.fromstring(xml_text)
        for item in root.findall('.//item'):
            ih = ''
            for attr in item.findall('.//t:attr', NS):
                if attr.get('name') == 'infohash':
                    ih = attr.get('value', '')
            if not ih:
                guid = item.findtext('guid', '')
                m = re.search(r'btih:([a-fA-F0-9]{40})', guid)
                if m: ih = m.group(1).lower()
            if not ih: continue
            title = item.findtext('title', 'Unknown')
            size_el = item.find('.//t:attr[@name="size"]', NS)
            size = int(float(size_el.get('value', 0))) if size_el is not None else 0
            seeds_el = item.find('.//t:attr[@name="seeders"]', NS)
            seeds = int(seeds_el.get('value', 0)) if seeds_el is not None else 0
            results.append({'title': title, 'hash': ih, 'size': size, 'seeders': seeds})
    except: pass
    return results

def detect_quality(name):
    n = name.lower()
    if any(x in n for x in ['2160', '4k', 'uhd']): return '🎬4K'
    if '1080' in n: return '📺1080p'
    if '720' in n: return '📺720p'
    if any(x in n for x in ['cam', 'ts.', 'tc.', 'tele']): return '📀SD'
    return '📀SD'

def fmt_size(bytes):
    if not bytes: return '?'
    gb = bytes / 1073741824
    if gb >= 1: return f'{gb:.2f} GB'
    mb = bytes / 1048576
    return f'{mb:.0f} MB'

PAGE = '''<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Ultimate Search</title>
<style>
*{{box-sizing:border-box;margin:0;padding:0}}
body{{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#0d1117;color:#e6edf3;max-width:960px;margin:0 auto;padding:20px}}
h1{{font-size:1.5rem;margin-bottom:20px;color:#58a6ff}}
.search-box{{display:flex;gap:8px;margin-bottom:20px}}
.search-box input[type=text]{{flex:1;padding:12px 16px;border:1px solid #30363d;border-radius:6px;background:#161b22;color:#e6edf3;font-size:1rem}}
.search-box input[type=text]:focus{{outline:none;border-color:#58a6ff}}
.search-box button{{padding:12px 24px;background:#238636;border:none;border-radius:6px;color:#fff;font-size:1rem;cursor:pointer}}
.search-box button:hover{{background:#2ea043}}
.filters{{display:flex;gap:16px;margin-bottom:20px;font-size:0.9rem;color:#8b949e}}
.filters label{{display:flex;align-items:center;gap:4px;cursor:pointer}}
table{{width:100%;border-collapse:collapse}}
th{{text-align:left;padding:8px 12px;border-bottom:2px solid #30363d;color:#8b949e;font-size:0.8rem;text-transform:uppercase;letter-spacing:0.05em}}
td{{padding:8px 12px;border-bottom:1px solid #21262d;font-size:0.9rem}}
tr:hover td{{background:#161b22}}
.hash{{font-family:'SF Mono','Fira Code',monospace;font-size:0.75rem;color:#8b949e}}
.size{{text-align:right;white-space:nowrap;color:#8b949e}}
.seeds{{text-align:right;white-space:nowrap;color:#8b949e}}
.quality{{white-space:nowrap}}
.action a{{color:#58a6ff;text-decoration:none;font-size:0.85rem}}
.action a:hover{{text-decoration:underline;color:#79c0ff}}
.title-cell{{max-width:400px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}}
.status{{padding:20px;text-align:center;color:#8b949e}}
.error{{color:#f85149}}
a{{color:#58a6ff}}
.footer{{margin-top:30px;padding-top:20px;border-top:1px solid #21262d;font-size:0.8rem;color:#8b949e}}
</style>
</head>
<body>
<h1>&#128270; Ultimate Search</h1>
<form class="search-box" method="get" action="/">
  <input type="text" name="q" placeholder="Movie or TV show title..." value="%s" autofocus>
  <button type="submit">Search</button>
</form>
<div class="filters">
  <label><input type="radio" name="type" value="movie" %s> Movie</label>
  <label><input type="radio" name="type" value="tv" %s> TV</label>
  <label><input type="checkbox" name="jackett" value="1" %s> Use Jackett</label>
  <span style="margin-left:auto">
    <button type="submit" style="background:none;border:none;color:#58a6ff;cursor:pointer;text-decoration:underline">Search</button>
  </span>
</div>
%s
<div class="footer">
TorrServer: %s
<a href="https://github.com/yourok/torrserver" target="_blank">TorrServer</a> &middot;
<a href="https://github.com/Jackett/Jackett" target="_blank">Jackett</a>
</div>
</body>
</html>'''

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        parsed = urllib.parse.urlparse(self.path)
        params = urllib.parse.parse_qs(parsed.query)
        path = parsed.path
        
        if path == '/settings':
            return self.serve_settings()
        
        if path == '/save_settings':
            return self.save_settings(params)
        
        # Serve static assets inline
        query = params.get('q', [''])[0]
        media_type = params.get('type', ['movie'])[0]
        use_jackett = params.get('jackett', [''])[0] == '1'
        
        results_html = '<div class="status">Enter a search query above</div>'
        
        if query:
            results_html = self.do_search(query, media_type, use_jackett)
        
        # Check TorrServer
        ts_alive = self.check_torrserver()
        ts_status = '<span style="color:#3fb950">●</span> Connected' if ts_alive else '<span style="color:#f85149">●</span> Not running'
        
        mchecked = 'checked' if media_type == 'movie' else ''
        tchecked = 'checked' if media_type == 'tv' else ''
        jchecked = 'checked' if use_jackett else ''
        
        html = self.render_page(query, media_type, use_jackett, results_html, ts_alive)
        
        self.send_response(200)
        self.send_header('Content-Type', 'text/html; charset=utf-8')
        self.end_headers()
        self.wfile.write(html.encode())
    
    def render_page(self, query, media_type, use_jackett, results_html, ts_alive):
        q = html.escape(query)
        m_ck = 'checked' if media_type == 'movie' else ''
        t_ck = 'checked' if media_type == 'tv' else ''
        j_ck = 'checked' if use_jackett else ''
        ts_s = '<span style="color:#3fb950">●</span> Connected' if ts_alive else '<span style="color:#f85149">●</span> Not running'
        
        return f'''<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Ultimate Search</title>
<style>
*{{box-sizing:border-box;margin:0;padding:0}}
body{{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#0d1117;color:#e6edf3;max-width:960px;margin:0 auto;padding:20px}}
h1{{font-size:1.5rem;margin-bottom:20px;color:#58a6ff}}
.search-box{{display:flex;gap:8px;margin-bottom:20px}}
.search-box input[type=text]{{flex:1;padding:12px 16px;border:1px solid #30363d;border-radius:6px;background:#161b22;color:#e6edf3;font-size:1rem}}
.search-box input[type=text]:focus{{outline:none;border-color:#58a6ff}}
.search-box button{{padding:12px 24px;background:#238636;border:none;border-radius:6px;color:#fff;font-size:1rem;cursor:pointer}}
.search-box button:hover{{background:#2ea043}}
.filters{{display:flex;gap:16px;margin-bottom:20px;font-size:0.9rem;color:#8b949e}}
.filters label{{display:flex;align-items:center;gap:4px;cursor:pointer}}
table{{width:100%;border-collapse:collapse}}
th{{text-align:left;padding:8px 12px;border-bottom:2px solid #30363d;color:#8b949e;font-size:0.8rem;text-transform:uppercase;letter-spacing:0.05em}}
td{{padding:8px 12px;border-bottom:1px solid #21262d;font-size:0.9rem}}
tr:hover td{{background:#161b22}}
.hash{{font-family:'SF Mono','Fira Code',monospace;font-size:0.75rem;color:#8b949e}}
.size{{text-align:right;white-space:nowrap;color:#8b949e}}
.seeds{{text-align:right;white-space:nowrap;color:#8b949e}}
.quality{{white-space:nowrap}}
.action a{{color:#58a6ff;text-decoration:none;font-size:0.85rem}}
.action a:hover{{text-decoration:underline;color:#79c0ff}}
.title-cell{{max-width:400px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}}
.status{{padding:20px;text-align:center;color:#8b949e}}
.error{{color:#f85149}}
a{{color:#58a6ff}}
.footer{{margin-top:30px;padding-top:20px;border-top:1px solid #21262d;font-size:0.8rem;color:#8b949e}}
</style>
</head>
<body>
<h1>&#128270; Ultimate Search</h1>
<form class="search-box" method="get" action="/">
  <input type="text" name="q" placeholder="Movie or TV show title..." value="{q}" autofocus>
  <button type="submit">Search</button>
</form>
<div class="filters">
  <label><input type="radio" name="type" value="movie" {m_ck}> Movie</label>
  <label><input type="radio" name="type" value="tv" {t_ck}> TV</label>
  <label><input type="checkbox" name="jackett" value="1" {j_ck}> Use Jackett</label>
  <span style="margin-left:auto">
    <a href="/settings">Settings</a>
    &middot;
    <a href="/" onclick="document.querySelector('.search-box input').value='';return true">Clear</a>
  </span>
</div>
{results_html}
<div class="footer">
TorrServer: {ts_s}
<a href="https://github.com/yourok/torrserver" target="_blank">TorrServer</a> &middot;
<a href="https://github.com/Jackett/Jackett" target="_blank">Jackett</a>
</div>
</body>
</html>'''
    
    def do_search(self, query, media_type, use_jackett):
        results = []
        
        # Try Jackett first if enabled
        if use_jackett:
            r = search_jackett(query, media_type)
            if r: results.extend(r)
        
        # Try Torznab/DMM as fallback
        if not results:
            r = search_dmm_torznab(query, media_type)
            if r: results.extend(r)
        
        if not results:
            return '<div class="status">No results found. Try a different query or enable Jackett.</div>'
        
        rows = []
        for r in results[:100]:
            title = html.escape(r.get('title', 'Unknown'))
            ih = r.get('hash', '')
            qual = detect_quality(title)
            size = fmt_size(r.get('size', 0))
            seeds = r.get('seeders', 0)
            magnet = f'magnet:?xt=urn:btih:{ih}&dn={urllib.parse.quote(title)}'
            
            ts_url = f'http://{TS_HOST}:{TS_PORT}/play?hash={ih}&file_id=0' if self.check_torrserver() else ''
            
            actions = f'<a href="{magnet}">Magnet</a>'
            if ts_url:
                actions += f' &middot; <a href="{ts_url}" target="_blank">Stream</a>'
            
            rows.append(f'''<tr>
<td class="title-cell" title="{title}">{title}</td>
<td class="quality">{qual}</td>
<td class="size">{size}</td>
<td class="seeds">{seeds}</td>
<td class="hash">{ih[:16]}...</td>
<td class="action">{actions}</td>
</tr>''')
        
        table = f'''<table>
<thead><tr>
<th>Title</th>
<th>Quality</th>
<th style="text-align:right">Size</th>
<th style="text-align:right">Seeds</th>
<th>Hash</th>
<th>Action</th>
</tr></thead>
<tbody>
{''.join(rows)}
</tbody>
</table>
<div class="status" style="text-align:left;padding:8px 12px">{len(results)} results</div>'''
        return table
    
    def check_torrserver(self):
        try:
            resp = urllib.request.urlopen(f'http://{TS_HOST}:{TS_PORT}/echo', timeout=2)
            return resp.read() == b'uptime'
        except: return False
    
    def serve_settings(self):
        page = f'''<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>Settings</title>
<style>body{{font-family:sans-serif;background:#0d1117;color:#e6edf3;max-width:600px;margin:20px auto;padding:20px}}
h1{{color:#58a6ff}} label{{display:block;margin:12px 0;font-size:0.9rem}}
input[type=text]{{width:100%;padding:8px;margin-top:4px;border:1px solid #30363d;border-radius:4px;background:#161b22;color:#e6edf3}}
button{{padding:10px 20px;background:#238636;border:none;border-radius:6px;color:#fff;cursor:pointer}}
a{{color:#58a6ff}}</style>
</head><body>
<h1>⚙️ Settings</h1>
<form method="get" action="/save_settings">
<label>TorrServer Host <input type="text" name="ts_host" value="{TS_HOST}"></label>
<label>TorrServer Port <input type="text" name="ts_port" value="{TS_PORT}"></label>
<label>Jackett Host <input type="text" name="jackett_host" value="{JACKETT_HOST}"></label>
<label>Jackett Port <input type="text" name="jackett_port" value="{JACKETT_PORT}"></label>
<label>Jackett API Key <input type="text" name="jackett_api" value="{JACKETT_API}"></label>
<button type="submit">Save</button>
</form>
<p><a href="/">← Back to search</a></p>
</body></html>'''
        self.send_response(200)
        self.send_header('Content-Type', 'text/html; charset=utf-8')
        self.end_headers()
        self.wfile.write(page.encode())
    
    def save_settings(self, params):
        global TS_HOST, TS_PORT, JACKETT_HOST, JACKETT_PORT, JACKETT_API
        TS_HOST = params.get('ts_host', [TS_HOST])[0]
        TS_PORT = params.get('ts_port', [str(TS_PORT)])[0]
        JACKETT_HOST = params.get('jackett_host', [JACKETT_HOST])[0]
        JACKETT_PORT = params.get('jackett_port', [JACKETT_PORT])[0]
        JACKETT_API = params.get('jackett_api', [JACKETT_API])[0]
        self.send_response(302)
        self.send_header('Location', '/')
        self.end_headers()
    
    def log_message(self, format, *args):
        print(f"[{self.client_address[0]}] {format % args}")

if __name__ == '__main__':
    server = HTTPServer((HOST, PORT), Handler)
    print(f"\n  🌐 Ultimate Search Web UI")
    print(f"  http://localhost:{PORT}")
    print(f"  http://192.168.1.50:{PORT}  (from network)")
    print(f"\n  Press Ctrl+C to stop\n")
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        server.shutdown()
