#!/bin/bash
echo "===================================================="
echo " INSTALADOR MASTER - IMPORTADOR XTREAM UI PRO (V20) "
echo "===================================================="

# 1. Instalar dependências base do Linux
echo "[1/6] Instalando dependências do sistema..."
apt-get update -y > /dev/null 2>&1
apt-get install -y python3 python3-pip python3-venv sqlite3 ufw curl > /dev/null 2>&1

# 2. Criar diretório do projeto
echo "[2/6] Criando ambiente de trabalho..."
DIR="/opt/xtream_importer"
mkdir -p $DIR
cd $DIR

# 3. Criar ambiente virtual e instalar bibliotecas Python
echo "[3/6] Instalando bibliotecas Python (Flask, Gunicorn, Cloudscraper)..."
python3 -m venv venv
source venv/bin/activate
pip install Flask Flask-SQLAlchemy Flask-Login requests pymysql werkzeug gunicorn cloudscraper > /dev/null 2>&1

# 4. Criar o cérebro do sistema (app.py)
echo "[4/6] Configurando o Motor de Importação..."
cat << 'EOF' > app.py
from flask import Flask, render_template, request, redirect, url_for, flash, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from werkzeug.security import generate_password_hash, check_password_hash
import pymysql, requests, re, threading, time, uuid, json, urllib.parse, os

app = Flask(__name__)
app.secret_key = 'chave_super_secreta_painel_top'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///painel.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

TEMP_FILE = '/opt/xtream_importer/temp_lista.m3u'

db = SQLAlchemy(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'

IMPORT_JOBS = {}

class Admin(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(50), unique=True, nullable=False)
    password_hash = db.Column(db.String(200), nullable=False)

class XtreamConfig(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    host = db.Column(db.String(100), default="localhost")
    port = db.Column(db.Integer, default=3306)
    user = db.Column(db.String(100), default="root")
    password = db.Column(db.String(200), default="")
    dbname = db.Column(db.String(100), default="xtream_iptvpro")
    tmdb_api_key = db.Column(db.String(100), default="f99aa9ae1fe7619969cc7db0938c1ae5")

@login_manager.user_loader
def load_user(user_id): return Admin.query.get(int(user_id))

@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated: return redirect(url_for('dashboard'))
    if request.method == 'POST':
        user = Admin.query.filter_by(username=request.form.get('username')).first()
        if user and check_password_hash(user.password_hash, request.form.get('password')):
            login_user(user)
            return redirect(url_for('dashboard'))
        flash('Usuário ou senha incorretos!', 'danger')
    return render_template('login.html')

@app.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for('login'))

@app.route('/')
@app.route('/dashboard')
@login_required
def dashboard(): return render_template('dashboard.html')

@app.route('/configuracoes', methods=['GET', 'POST'])
@login_required
def configuracoes():
    config = XtreamConfig.query.first()
    if request.method == 'POST':
        action = request.form.get('action')
        if action == 'update_xtream':
            config.host = request.form.get('host')
            config.port = request.form.get('port')
            config.user = request.form.get('user')
            config.password = request.form.get('password')
            config.dbname = request.form.get('dbname')
            config.tmdb_api_key = request.form.get('tmdb_api_key')
            db.session.commit()
            flash('Configurações salvas!', 'success')
            return redirect(url_for('configuracoes'))
        elif action == 'update_admin':
            if request.form.get('admin_user') and request.form.get('admin_pass'):
                current_user.username = request.form.get('admin_user')
                current_user.password_hash = generate_password_hash(request.form.get('admin_pass'))
                db.session.commit()
                flash('Credenciais atualizadas!', 'success')
                return redirect(url_for('configuracoes'))
    return render_template('settings.html', config=config)

@app.route('/limpar_banco', methods=['POST'])
@login_required
def limpar_banco():
    dados = request.json
    config = XtreamConfig.query.first()
    try:
        conn = pymysql.connect(host=config.host, port=config.port, user=config.user, password=config.password, database=config.dbname)
        cursor = conn.cursor()
        if dados.get('live'):
            cursor.execute("DELETE FROM streams WHERE type = 1 OR type = 8")
            cursor.execute("DELETE FROM stream_categories WHERE category_type = 'live'")
        if dados.get('vod'):
            cursor.execute("DELETE FROM streams WHERE type = 2")
            cursor.execute("DELETE FROM stream_categories WHERE category_type = 'movie'")
        if dados.get('series'):
            cursor.execute("DELETE FROM series")
            cursor.execute("DELETE FROM series_episodes")
            try: cursor.execute("DELETE FROM streams_seasons") 
            except: pass
            cursor.execute("DELETE FROM streams WHERE type = 5")
            cursor.execute("DELETE FROM stream_categories WHERE category_type = 'series'")
        conn.commit()
        conn.close()
        return jsonify({"status": "success", "msg": "Banco limpo com sucesso!"})
    except Exception as e: return jsonify({"status": "error", "msg": str(e)})

def baixar_lista_blindada(link):
    if os.path.exists(TEMP_FILE): os.remove(TEMP_FILE)
    try:
        r = requests.get(link, headers={'User-Agent': 'IPTVSmartersPro'}, stream=True, timeout=15)
        if r.status_code == 200:
            with open(TEMP_FILE, 'wb') as f:
                for chunk in r.iter_content(chunk_size=8192): f.write(chunk)
            if os.path.getsize(TEMP_FILE) > 1000: return True
    except: pass
    try:
        proxy_url = f"https://api.codetabs.com/v1/proxy?quest={link}"
        r = requests.get(proxy_url, stream=True, timeout=60)
        if r.status_code == 200:
            with open(TEMP_FILE, 'wb') as f:
                for chunk in r.iter_content(chunk_size=8192): f.write(chunk)
            if os.path.getsize(TEMP_FILE) > 1000: return True
    except: pass
    return False

@app.route('/analisar_m3u', methods=['POST'])
@login_required
def analisar_m3u():
    file = request.files.get('m3u_file')
    link = request.form.get('m3u_link')
    try:
        config = XtreamConfig.query.first()
        bouquets_list = []
        try:
            conn = pymysql.connect(host=config.host, port=config.port, user=config.user, password=config.password, database=config.dbname)
            cursor = conn.cursor()
            cursor.execute("SELECT id, bouquet_name FROM bouquets ORDER BY bouquet_order ASC")
            for row in cursor.fetchall(): bouquets_list.append({"id": row[0], "name": row[1]})
            conn.close()
        except: pass

        if file and file.filename: file.save(TEMP_FILE)
        elif link:
            if not baixar_lista_blindada(link): return jsonify({"status": "error", "msg": "Bloqueio de IP detectado. Use a aba 'Arquivo .M3U'."})
        else: return jsonify({"status": "error", "msg": "Nenhum arquivo enviado."})

        categorias = set()
        with open(TEMP_FILE, 'r', encoding='utf-8', errors='ignore') as f:
            for linha in f:
                if linha.startswith('#EXTINF'):
                    match = re.search(r'group-title=["\']?([^"\',]+)["\']?', linha)
                    if match: categorias.add(match.group(1).strip())
        cats = sorted(list(categorias))
        if not cats: return jsonify({"status": "error", "msg": "Sem categorias. Adicione &type=m3u_plus ao final do link."})
        return jsonify({"status": "success", "categorias": cats, "bouquets": bouquets_list})
    except Exception as e: return jsonify({"status": "error", "msg": str(e)})

def limpar_nome(nome):
    nome = re.sub(r'(?i)\[.*?\]|\(.*?\)', '', nome) 
    nome = re.sub(r'(?i)(S\d+E\d+|T\d+E\d+).*', '', nome)
    nome = re.sub(r'(?i)\b(S\d+|T\d+)\b.*', '', nome)
    nome = re.sub(r'(?i)\s*-\s*Parte.*', '', nome) 
    nome = re.sub(r'(?i)4K|FHD|HD|3D|LEG|DUB', '', nome) 
    return nome.strip()

def extrair_temporada_episodio(nome):
    season, episode = 1, 1
    m_s = re.search(r'(?i)(?:S|T)(\d+)', nome)
    if m_s: season = int(m_s.group(1))
    m_e = re.search(r'(?i)E(\d+)', nome)
    if m_e: episode = int(m_e.group(1))
    elif m_s:
        m_se = re.search(rf'(?i)(?:S|T){season}\s*[-xX]\s*(\d+)', nome)
        if m_se: episode = int(m_se.group(1))
        else:
            m_last = re.findall(r'\b\d+\b', nome)
            if m_last and int(m_last[-1]) != season: episode = int(m_last[-1])
    return season, episode

def buscar_tmdb(titulo, tipo, api_key):
    if not api_key: return None
    url = f"https://api.themoviedb.org/3/search/{tipo}?api_key={api_key}&query={urllib.parse.quote(titulo)}&language=pt-BR"
    try:
        res = requests.get(url, timeout=5).json()
        if res.get('results') and len(res['results']) > 0:
            item = res['results'][0]
            img_base = "https://image.tmdb.org/t/p/w500"
            return {
                "tmdb_id": str(item.get('id', '')), "title": item.get('title') if tipo == 'movie' else item.get('name'),
                "cover": f"{img_base}{item['poster_path']}" if item.get('poster_path') else "",
                "plot": item.get('overview', ''), "rating": item.get('vote_average', 0),
                "release_date": item.get('release_date', '') if tipo == 'movie' else item.get('first_air_date', '')
            }
    except: pass
    return None

def log_msg(job_id, msg):
    if len(IMPORT_JOBS[job_id]["logs"]) > 100: IMPORT_JOBS[job_id]["logs"].pop(0)
    IMPORT_JOBS[job_id]["logs"].append(f"[{time.strftime('%H:%M:%S')}] {msg}")

def adicionar_ao_relatorio(job_id, tipo, categoria, nome):
    if categoria not in IMPORT_JOBS[job_id]["relatorio"][tipo]:
        IMPORT_JOBS[job_id]["relatorio"][tipo][categoria] = []
    if nome not in IMPORT_JOBS[job_id]["relatorio"][tipo][categoria]:
        IMPORT_JOBS[job_id]["relatorio"][tipo][categoria].append(nome)

def processar_importacao(job_id, categorias_selecionadas, bouquets_selecionados, config_id):
    with app.app_context():
        config = XtreamConfig.query.get(config_id)
        log_msg(job_id, "Iniciando Leitura do Cache Local...")
        try:
            conn = pymysql.connect(host=config.host, port=config.port, user=config.user, password=config.password, database=config.dbname)
            cursor = conn.cursor()
            
            with open(TEMP_FILE, 'r', encoding='utf-8', errors='ignore') as f: linhas = f.readlines()
                
            conteudos = []
            info_atual = None
            for linha in linhas:
                linha = linha.strip()
                if linha.startswith('#EXTINF'): info_atual = linha
                elif linha.startswith('http') and info_atual:
                    match_cat = re.search(r'group-title=["\']?([^"\',]+)["\']?', info_atual)
                    if match_cat and match_cat.group(1).strip() in categorias_selecionadas:
                        conteudos.append({"info": info_atual, "url": linha, "categoria": match_cat.group(1).strip()})
                    info_atual = None

            total = len(conteudos)
            IMPORT_JOBS[job_id]["total"] = total
            novos_stream_ids, novos_series_ids, series_cache = set(), set(), {}

            for i, item in enumerate(conteudos):
                if IMPORT_JOBS[job_id].get("cancelar"):
                    log_msg(job_id, "⚠️ CANCELADO!"); IMPORT_JOBS[job_id]["status"] = "cancelado"; break
                while IMPORT_JOBS[job_id].get("pausado"):
                    time.sleep(1)
                    if IMPORT_JOBS[job_id].get("cancelar"): break
                if IMPORT_JOBS[job_id].get("cancelar"): break

                nome_match = re.search(r',(.*)$', item["info"])
                nome_bruto = nome_match.group(1) if nome_match else "Sem Nome"
                nome_limpo_pesquisa = limpar_nome(nome_bruto)
                logo_match = re.search(r'tvg-logo="([^"]+)"', item["info"])
                logo_original = logo_match.group(1) if logo_match else ""
                cat_nome = item["categoria"]
                cat_nome_lower = cat_nome.lower()
                
                if "série" in cat_nome_lower or "serie" in cat_nome_lower: tipo_cat_nome, tipo_num = "series", 5
                elif "filme" in cat_nome_lower or "vod" in cat_nome_lower or item["url"].endswith(('.mp4', '.mkv')): tipo_cat_nome, tipo_num = "movie", 2
                else: tipo_cat_nome, tipo_num = "live", 1

                cursor.execute("SELECT id FROM stream_categories WHERE category_name = %s AND category_type = %s", (cat_nome, tipo_cat_nome))
                cat_existente = cursor.fetchone()
                if not cat_existente:
                    cursor.execute("INSERT INTO stream_categories (category_type, category_name) VALUES (%s, %s)", (tipo_cat_nome, cat_nome))
                    conn.commit(); cat_id = cursor.lastrowid
                else: cat_id = cat_existente[0]

                source_json = json.dumps([item['url']]).replace('/', '\\/')

                if tipo_cat_nome == "series":
                    nome_serie = nome_limpo_pesquisa
                    season_num, ep_num = extrair_temporada_episodio(nome_bruto)
                    cursor.execute("SELECT id FROM series WHERE title = %s", (nome_serie,))
                    serie_existente = cursor.fetchone()
                    if not serie_existente:
                        tmdb = series_cache.get(nome_serie)
                        if not tmdb:
                            tmdb = buscar_tmdb(nome_serie, 'tv', config.tmdb_api_key); series_cache[nome_serie] = tmdb
                        capa = tmdb['cover'] if tmdb else logo_original
                        cursor.execute("""INSERT INTO series (title, category_id, cover, cover_big, plot, rating, releaseDate, tmdb_id, last_modified) 
                            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)""", (nome_serie, cat_id, capa, capa, tmdb['plot'] if tmdb else "", tmdb['rating'] if tmdb else 0, tmdb['release_date'] if tmdb else "", tmdb['tmdb_id'] if tmdb else "", int(time.time())))
                        conn.commit(); serie_id = cursor.lastrowid
                    else: serie_id = serie_existente[0]
                    novos_series_ids.add(serie_id)

                    cursor.execute("SELECT id FROM streams WHERE stream_display_name = %s AND category_id = %s", (nome_bruto, cat_id))
                    if cursor.fetchone(): 
                        IMPORT_JOBS[job_id]["ignorados"] += 1
                        log_msg(job_id, f"🔄 [PULADO] Já existe: {nome_bruto}")
                    else:
                        cursor.execute("""INSERT INTO streams (type, category_id, stream_display_name, stream_source, stream_icon, direct_source, added, stream_all) 
                            VALUES (%s, %s, %s, %s, %s, %s, %s, %s)""", (tipo_num, cat_id, nome_bruto, source_json, logo_original, 1, int(time.time()), 1))
                        conn.commit(); stream_id = cursor.lastrowid
                        cursor.execute("INSERT INTO series_episodes (season_num, series_id, stream_id, sort) VALUES (%s, %s, %s, %s)", (season_num, serie_id, stream_id, ep_num))
                        conn.commit()
                        log_msg(job_id, f"🎬 [SÉRIE] Adicionado: {nome_bruto}")
                        adicionar_ao_relatorio(job_id, 'series', cat_nome, nome_bruto)

                else:
                    cursor.execute("SELECT id FROM streams WHERE stream_display_name = %s AND category_id = %s", (nome_bruto, cat_id))
                    if cursor.fetchone(): 
                        IMPORT_JOBS[job_id]["ignorados"] += 1
                        log_msg(job_id, f"🔄 [PULADO] Já existe: {nome_bruto}")
                    else:
                        capa, prop_json, sinopse_txt = logo_original, "{}", ""
                        if tipo_cat_nome == "movie":
                            tmdb = buscar_tmdb(nome_limpo_pesquisa, 'movie', config.tmdb_api_key)
                            if tmdb:
                                capa, sinopse_txt = tmdb['cover'], tmdb['plot']
                                prop_json = json.dumps({"tmdb_id": tmdb['tmdb_id'], "name": tmdb['title'], "o_name": tmdb['title'], "cover_big": tmdb['cover'], "movie_image": tmdb['cover'], "plot": tmdb['plot'], "description": tmdb['plot'], "cast": "", "director": "", "genre": "", "release_date": tmdb['release_date'], "rating": str(tmdb['rating']), "duration": ""}, ensure_ascii=False)
                        
                        cursor.execute("""INSERT INTO streams (type, category_id, stream_display_name, stream_source, stream_icon, notes, direct_source, added, stream_all, movie_propeties) 
                            VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""", (tipo_num, cat_id, nome_bruto, source_json, capa, sinopse_txt, 1, int(time.time()), 1, prop_json))
                        conn.commit(); novos_stream_ids.add(cursor.lastrowid)
                        
                        if tipo_cat_nome == "movie":
                            log_msg(job_id, f"📽️ [FILME] Adicionado: {nome_bruto}")
                            adicionar_ao_relatorio(job_id, 'movie', cat_nome, nome_bruto)
                        else:
                            log_msg(job_id, f"📺 [CANAL] Adicionado: {nome_bruto}")
                            adicionar_ao_relatorio(job_id, 'live', cat_nome, nome_bruto)

                IMPORT_JOBS[job_id]["atual"] = i + 1
                IMPORT_JOBS[job_id]["progress"] = int(((i + 1) / total) * 100)
                
            if bouquets_selecionados and IMPORT_JOBS[job_id]["status"] != "cancelado":
                log_msg(job_id, "Salvando nos Pacotes...")
                for b_id in bouquets_selecionados:
                    cursor.execute("SELECT bouquet_channels, bouquet_series, bouquet_name FROM bouquets WHERE id = %s", (b_id,))
                    b_data = cursor.fetchone()
                    if b_data:
                        try:
                            def limpa_array(str_val):
                                if not str_val or str_val == 'null': return set()
                                return set([int(x) for x in str_val.replace('[','').replace(']','').replace('"','').replace("'",'').split(',') if x.strip().isdigit()])
                            c_existentes = limpa_array(b_data[0]); c_existentes.update(novos_stream_ids)
                            s_existentes = limpa_array(b_data[1]); s_existentes.update(novos_series_ids)
                            str_canais = "[" + ",".join(map(str, sorted(list(c_existentes)))) + "]"
                            str_series = "[" + ",".join(map(str, sorted(list(s_existentes)))) + "]"
                            cursor.execute("UPDATE bouquets SET bouquet_channels = %s, bouquet_series = %s WHERE id = %s", (str_canais, str_series, b_id))
                            conn.commit()
                        except: pass

            conn.close()
            if IMPORT_JOBS[job_id]["status"] != "cancelado":
                log_msg(job_id, "✅ IMPORTAÇÃO FINALIZADA COM SUCESSO!")
                IMPORT_JOBS[job_id]["status"] = "concluido"
        except Exception as e:
            log_msg(job_id, f"❌ ERRO FATAL: {str(e)}"); IMPORT_JOBS[job_id]["status"] = "erro"

@app.route('/iniciar_importacao', methods=['POST'])
@login_required
def iniciar_importacao():
    dados = request.json
    job_id = str(uuid.uuid4())
    IMPORT_JOBS[job_id] = {"status": "rodando", "progress": 0, "total": 0, "atual": 0, "ignorados": 0, "logs": [], "pausado": False, "cancelar": False, "relatorio": {"movie": {}, "series": {}, "live": {}}}
    thread = threading.Thread(target=processar_importacao, args=(job_id, dados.get('categorias', []), dados.get('bouquets', []), XtreamConfig.query.first().id))
    thread.daemon = True; thread.start()
    return jsonify({"status": "success", "job_id": job_id})

@app.route('/get_active_job', methods=['GET'])
@login_required
def get_active_job():
    for job_id, job_data in IMPORT_JOBS.items():
        if job_data["status"] == "rodando": return jsonify({"status": "found", "job_id": job_id})
    return jsonify({"status": "none"})

@app.route('/controle_job/<job_id>/<acao>', methods=['POST'])
@login_required
def controle_job(job_id, acao):
    if job_id in IMPORT_JOBS:
        if acao == 'pausar': IMPORT_JOBS[job_id]["pausado"] = True; IMPORT_JOBS[job_id]["logs"].append("⏸️ Importação Pausada...")
        elif acao == 'continuar': IMPORT_JOBS[job_id]["pausado"] = False; IMPORT_JOBS[job_id]["logs"].append("▶️ Retomando Importação...")
        elif acao == 'cancelar': IMPORT_JOBS[job_id]["cancelar"] = True
        return jsonify({"status": "success"})
    return jsonify({"status": "error"})

@app.route('/status_importacao/<job_id>', methods=['GET'])
@login_required
def status_importacao(job_id):
    job = IMPORT_JOBS.get(job_id)
    return jsonify(job) if job else jsonify({"status": "nao_encontrado"})

@app.route('/gerar_relatorio/<job_id>', methods=['GET'])
@login_required
def gerar_relatorio(job_id):
    job = IMPORT_JOBS.get(job_id)
    if not job: return jsonify({"texto": ""})
    
    data_atual = time.strftime('%d/%m/%Y')
    linhas = [f"Atualização conteúdos do dia: {data_atual}\n"]
    
    mapeamento = [('movie', '[FILMES]', '📽️'), ('series', '[SÉRIES]', '🎬'), ('live', '[CANAIS]', '📺')]
    
    for tipo_chave, titulo, icone in mapeamento:
        categorias = job["relatorio"].get(tipo_chave, {})
        if categorias:
            linhas.append(f"\n{titulo}\n")
            for cat, itens in categorias.items():
                linhas.append(f"📁 {cat}\n")
                for item in itens:
                    linhas.append(f"{icone} {item}")
                linhas.append("")
                
    return jsonify({"texto": "\n".join(linhas)})

@app.route('/limpar_sessao', methods=['POST'])
@login_required
def limpar_sessao():
    IMPORT_JOBS.clear()
    return jsonify({"status": "success"})

with app.app_context():
    db.create_all()
    if not Admin.query.first():
        db.session.add(Admin(username='admin', password_hash=generate_password_hash('admin123')))
        db.session.add(XtreamConfig(tmdb_api_key="f99aa9ae1fe7619969cc7db0938c1ae5"))
        db.session.commit()

if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
EOF

# 5. Criar Telas (Mobile, UI, Hambúrguer, WhatsApp)
echo "[5/6] Construindo o visual da plataforma..."
mkdir -p templates

cat << 'EOF' > templates/base.html
<!DOCTYPE html>
<html lang="pt-BR" data-bs-theme="dark">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>Painel de Importação</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <style>
        body { background-color: #121212; font-family: 'Segoe UI', sans-serif; overflow-x: hidden; } 
        .card { background-color: #1e1e1e; border: 1px solid #333; } 
        .form-control { background-color: #2a2a2a; border: 1px solid #444; color: #fff; }
        .log-box { white-space: pre-wrap; word-break: break-word; font-size: 13px; line-height: 1.4; }
    </style>
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-dark mb-4" style="background-color: #1e1e1e; border-bottom: 1px solid #333;">
        <div class="container">
            <a class="navbar-brand fw-bold text-primary" href="{{ url_for('dashboard') }}"><i class="fa-solid fa-cloud-arrow-up me-2"></i>Importador PRO</a>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarNav">
                <ul class="navbar-nav ms-auto">
                    <li class="nav-item"><a class="nav-link" href="{{ url_for('dashboard') }}"><i class="fa-solid fa-house me-1"></i> Início</a></li>
                    <li class="nav-item"><a class="nav-link" href="{{ url_for('configuracoes') }}"><i class="fa-solid fa-gear me-1"></i> Configurações</a></li>
                    <li class="nav-item"><a class="nav-link text-danger fw-bold" href="{{ url_for('logout') }}"><i class="fa-solid fa-right-from-bracket me-1"></i> Sair</a></li>
                </ul>
            </div>
        </div>
    </nav>
    <div class="container px-3">
        {% with messages = get_flashed_messages(with_categories=true) %}{% if messages %}{% for category, message in messages %}<div class="alert alert-{{ category }}">{{ message }}</div>{% endfor %}{% endif %}{% endwith %}
        {% block content %}{% endblock %}
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body></html>
EOF

cat << 'EOF' > templates/login.html
<!DOCTYPE html>
<html lang="pt-BR" data-bs-theme="dark">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>Login - Importador PRO</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
</head>
<body style="background-color: #121212; display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 20px;">
<div class="card p-4 w-100" style="background-color: #1e1e1e; max-width: 380px; border: 1px solid #333; box-shadow: 0 10px 30px rgba(0,0,0,0.5); border-radius: 12px;">
    <div class="text-center mb-4">
        <h2 class="text-primary fw-bold"><i class="fa-solid fa-cloud-arrow-up"></i></h2>
        <h4 class="text-white fw-bold">Importador PRO</h4>
        <p class="text-muted small">Acesso Restrito</p>
    </div>
    <form method="POST">
        <input type="text" name="username" class="form-control mb-3 py-2" placeholder="Usuário" required style="background-color: #2a2a2a; border: 1px solid #444; color: #fff;">
        <input type="password" name="password" class="form-control mb-4 py-2" placeholder="Senha" required style="background-color: #2a2a2a; border: 1px solid #444; color: #fff;">
        <button class="btn btn-primary w-100 py-2 fw-bold fs-5">Entrar</button>
    </form>
</div>
</body></html>
EOF

cat << 'EOF' > templates/settings.html
{% extends "base.html" %}
{% block content %}
<div class="row"><div class="col-md-6 mb-4"><div class="card p-4"><h5 class="text-primary mb-3"><i class="fa-solid fa-database me-2"></i>Banco Xtream UI</h5><form method="POST"><input type="hidden" name="action" value="update_xtream"><input type="text" class="form-control mb-2" name="host" value="{{ config.host }}" placeholder="Host"><input type="number" class="form-control mb-2" name="port" value="{{ config.port }}" placeholder="Porta"><input type="text" class="form-control mb-2" name="user" value="{{ config.user }}" placeholder="Usuário"><input type="password" class="form-control mb-2" name="password" value="{{ config.password }}" placeholder="Senha"><input type="text" class="form-control mb-3" name="dbname" value="{{ config.dbname }}" placeholder="Nome do Banco"><input type="text" class="form-control mb-3" name="tmdb_api_key" value="{{ config.tmdb_api_key }}" placeholder="TMDB API Key"><button class="btn btn-primary w-100">Salvar Conexão</button></form></div></div><div class="col-md-6 mb-4"><div class="card p-4"><h5 class="text-primary mb-3"><i class="fa-solid fa-lock me-2"></i>Segurança</h5><form method="POST"><input type="hidden" name="action" value="update_admin"><input type="text" class="form-control mb-2" name="admin_user" value="{{ current_user.username }}"><input type="password" class="form-control mb-3" name="admin_pass" placeholder="Nova Senha"><button class="btn btn-danger w-100">Atualizar Acesso</button></form></div></div></div>
{% endblock %}
EOF

cat << 'EOF' > templates/dashboard.html
{% extends "base.html" %}
{% block content %}
<div class="row mb-4 d-flex justify-content-between align-items-center">
    <div class="col-7"><h4 class="fw-bold m-0 text-white">Gerenciador</h4></div>
    <div class="col-5 text-end"><button class="btn btn-sm btn-danger fw-bold shadow" data-bs-toggle="modal" data-bs-target="#modalLimpeza"><i class="fa-solid fa-trash"></i> Limpar DB</button></div>
</div>

<div class="modal fade" id="modalLimpeza"><div class="modal-dialog modal-dialog-centered"><div class="modal-content bg-dark border-secondary"><div class="modal-header border-secondary"><h5 class="modal-title text-danger fw-bold"><i class="fa-solid fa-triangle-exclamation me-2"></i> Apagar Dados</h5><button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button></div><div class="modal-body"><div class="form-check form-switch fs-5 mb-3"><input type="checkbox" class="form-check-input" id="wipeLive"><label class="form-check-label text-info"><i class="fa-solid fa-tv me-2"></i>Canais</label></div><div class="form-check form-switch fs-5 mb-3"><input type="checkbox" class="form-check-input" id="wipeVod"><label class="form-check-label text-warning"><i class="fa-solid fa-film me-2"></i>Filmes</label></div><div class="form-check form-switch fs-5"><input type="checkbox" class="form-check-input" id="wipeSeries"><label class="form-check-label text-success"><i class="fa-solid fa-video me-2"></i>Séries</label></div></div><div class="modal-footer border-secondary"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button><button type="button" class="btn btn-danger fw-bold w-100 mt-2" onclick="executarLimpeza()">Confirmar Exclusão</button></div></div></div></div>

<div class="row" id="areaConfig">
    <div class="col-12">
        <div class="card p-3 mb-4 shadow-sm">
            <ul class="nav nav-pills mb-3 nav-justified" id="pills-tab" role="tablist">
              <li class="nav-item" role="presentation"><button class="nav-link active fw-bold py-2" id="tab-link" data-bs-toggle="pill" data-bs-target="#pane-link" type="button">Link URL</button></li>
              <li class="nav-item" role="presentation"><button class="nav-link fw-bold py-2" id="tab-file" data-bs-toggle="pill" data-bs-target="#pane-file" type="button">Arquivo .M3U</button></li>
            </ul>
            <div class="tab-content mb-3" id="pills-tabContent">
              <div class="tab-pane fade show active" id="pane-link"><input type="url" class="form-control py-2" id="m3u_link" placeholder="http://...&type=m3u_plus"></div>
              <div class="tab-pane fade" id="pane-file"><input type="file" class="form-control py-2" id="m3u_file" accept=".m3u,.m3u8,.txt"></div>
            </div>
            <button class="btn btn-primary w-100 fw-bold py-2 fs-5" id="btnAnalisar" onclick="analisarLista()"><i class="fa-solid fa-magnifying-glass me-2"></i> Analisar Lista</button>
        </div>

        <div class="card p-3 shadow-sm" id="areaCategorias" style="display:none;">
            <h5 class="fw-bold text-info"><i class="fa-solid fa-list me-2"></i>Categorias</h5>
            <div class="d-flex gap-2 mb-2"><button class="btn btn-sm btn-outline-info flex-grow-1" onclick="selecionarTodos('.cat-checkbox', true)">Marcar Todos</button><button class="btn btn-sm btn-outline-secondary flex-grow-1" onclick="selecionarTodos('.cat-checkbox', false)">Desmarcar</button></div>
            <div id="listaCategorias" class="mb-4 bg-black rounded p-2" style="height:200px; overflow-y:auto; border:1px solid #444;"></div>
            
            <h5 class="fw-bold text-warning"><i class="fa-solid fa-box-open me-2"></i>Pacotes (Bouquets)</h5>
            <div class="d-flex gap-2 mb-2"><button class="btn btn-sm btn-outline-warning flex-grow-1" onclick="selecionarTodos('.bq-checkbox', true)">Marcar Todos</button><button class="btn btn-sm btn-outline-secondary flex-grow-1" onclick="selecionarTodos('.bq-checkbox', false)">Desmarcar</button></div>
            <div id="listaBouquets" class="mb-3 bg-black rounded p-2" style="height:150px; overflow-y:auto; border:1px solid #444;"></div>
            
            <button class="btn btn-success w-100 py-3 fs-5 fw-bold shadow" onclick="iniciarImportacaoReal()"><i class="fa-solid fa-cloud-arrow-down me-2"></i> INICIAR IMPORTAÇÃO</button>
        </div>
    </div>
</div>

<div class="row" id="areaProgresso" style="display:none;">
    <div class="col-12">
        <div class="card p-3 border-primary shadow">
            <h5 class="text-primary mb-3 fw-bold" id="textStatus"><i class="fa-solid fa-gears fa-spin me-2" id="iconStatus"></i> Importando...</h5>
            
            <div class="d-flex justify-content-between mb-1 small"><span class="fw-bold" id="txtProgresso">Calculando...</span><span class="badge bg-danger ms-auto me-2" id="txtIgnorados">0 Ignorados</span><span class="fw-bold" id="txtPorcentagem">0%</span></div>
            <div class="progress mb-3" style="height:22px; background-color:#222; border-radius:10px;"><div id="barraProgresso" class="progress-bar bg-success progress-bar-animated progress-bar-striped fw-bold" style="width:0%; line-height:22px;"></div></div>
            
            <div id="logTerminal" class="bg-black text-success p-2 rounded mb-3 log-box" style="height:280px; overflow-y:auto; border:1px solid #444; box-shadow: inset 0 0 10px #000;"></div>
            
            <div class="d-flex gap-2 mb-3" id="areaControles">
                <button class="btn btn-warning flex-grow-1 fw-bold py-2" id="btnPausar" onclick="controleJob('pausar')"><i class="fa-solid fa-pause"></i> Pausar</button>
                <button class="btn btn-success flex-grow-1 fw-bold py-2" id="btnContinuar" onclick="controleJob('continuar')" style="display:none;"><i class="fa-solid fa-play"></i> Continuar</button>
                <button class="btn btn-danger flex-grow-1 fw-bold py-2" onclick="controleJob('cancelar')"><i class="fa-solid fa-stop"></i> Cancelar</button>
            </div>
            
            <div id="areaRelatorio" style="display:none;" class="mt-3">
                <h6 class="fw-bold text-white"><i class="fa-brands fa-whatsapp text-success me-2"></i>Relatório da Atualização</h6>
                <textarea id="textoRelatorio" class="form-control bg-black text-white mb-2" style="height: 150px; font-size:12px; resize:none;" readonly></textarea>
                <div class="d-flex gap-2 mb-3">
                    <button class="btn btn-secondary flex-grow-1 fw-bold" onclick="copiarRelatorio()"><i class="fa-regular fa-copy me-2"></i>Copiar</button>
                    <button class="btn btn-success flex-grow-1 fw-bold" onclick="enviarWhatsApp()"><i class="fa-brands fa-whatsapp me-2"></i>Enviar Zap</button>
                </div>
            </div>

            <button class="btn btn-outline-primary w-100 fw-bold py-2" id="btnNova" style="display:none;" onclick="novaImportacao()"><i class="fa-solid fa-rotate-right me-2"></i> Fazer Nova Importação</button>
        </div>
    </div>
</div>

<script>
let currentJobId = null, monitorInterval = null;
window.onload = () => { fetch('/get_active_job').then(r=>r.json()).then(d=>{if(d.status==='found'){currentJobId=d.job_id; document.getElementById('areaConfig').style.display='none'; document.getElementById('areaProgresso').style.display='block'; monitorInterval=setInterval(verificarStatus, 1000);}}); };

function executarLimpeza() { const d={live:document.getElementById('wipeLive').checked, vod:document.getElementById('wipeVod').checked, series:document.getElementById('wipeSeries').checked}; if(!d.live && !d.vod && !d.series) { alert("Selecione um item!"); return; } if(confirm("Certeza absoluta?")) fetch('/limpar_banco',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(d)}).then(r=>r.json()).then(res=>{alert(res.msg); location.reload();}); }

function analisarLista() {
    const fd = new FormData(), isFile = document.getElementById('tab-file').classList.contains('active');
    if(isFile) { const fileInput = document.getElementById('m3u_file'); if(fileInput.files.length === 0) { alert("Selecione o arquivo!"); return; } fd.append('m3u_file', fileInput.files[0]); } 
    else { const link = document.getElementById('m3u_link').value; if(!link) { alert("Insira o link!"); return; } fd.append('m3u_link', link); }
    
    document.getElementById('btnAnalisar').innerHTML = '<i class="fa-solid fa-spinner fa-spin me-2"></i> Aguarde...';
    fetch('/analisar_m3u',{method:'POST',body:fd}).then(r=>r.json()).then(d=>{
        document.getElementById('btnAnalisar').innerHTML = '<i class="fa-solid fa-magnifying-glass me-2"></i> Analisar Lista';
        if(d.status==='success'){
            document.getElementById('areaCategorias').style.display='block'; 
            document.getElementById('listaCategorias').innerHTML=d.categorias.map((c,i)=>`<div class="form-check mb-1"><input type="checkbox" class="form-check-input cat-checkbox" value="${c}" id="c${i}"><label class="form-check-label text-light small" for="c${i}">${c}</label></div>`).join(''); 
            document.getElementById('listaBouquets').innerHTML=d.bouquets.map(b=>`<div class="form-check mb-1"><input type="checkbox" class="form-check-input bq-checkbox" value="${b.id}" id="b${b.id}"><label class="text-warning fw-bold small" for="b${b.id}">${b.name}</label></div>`).join('');
        } else alert(d.msg);
    }).catch(e => { alert("Erro de conexão!"); document.getElementById('btnAnalisar').innerHTML = '<i class="fa-solid fa-magnifying-glass me-2"></i> Analisar Lista'; });
}

function selecionarTodos(c, e) { document.querySelectorAll(c).forEach(x=>x.checked=e); }

function iniciarImportacaoReal() {
    const c=Array.from(document.querySelectorAll('.cat-checkbox:checked')).map(x=>x.value), b=Array.from(document.querySelectorAll('.bq-checkbox:checked')).map(x=>x.value);
    if(!c.length) { alert("Selecione ao menos 1 categoria!"); return; }
    document.getElementById('areaConfig').style.display='none'; document.getElementById('areaProgresso').style.display='block'; 
    fetch('/iniciar_importacao',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({categorias:c,bouquets:b})}).then(r=>r.json()).then(d=>{if(d.status==='success'){currentJobId=d.job_id; monitorInterval=setInterval(verificarStatus, 1000);}}); 
}

function controleJob(a) { 
    if(a==='cancelar' && !confirm("Deseja cancelar?")) return;
    fetch(`/controle_job/${currentJobId}/${a}`,{method:'POST'}).then(()=>{if(a==='pausar'){document.getElementById('btnPausar').style.display='none'; document.getElementById('btnContinuar').style.display='block'; document.getElementById('iconStatus').classList.remove('fa-spin'); document.getElementById('textStatus').innerText='Pausado';} else if(a==='continuar'){document.getElementById('btnPausar').style.display='block'; document.getElementById('btnContinuar').style.display='none'; document.getElementById('iconStatus').classList.add('fa-spin'); document.getElementById('textStatus').innerHTML='<i class="fa-solid fa-gears fa-spin me-2" id="iconStatus"></i> Importando...';}}); 
}

function verificarStatus() { 
    fetch('/status_importacao/'+currentJobId).then(r=>r.json()).then(d=>{
        if(d.status==='nao_encontrado')return; 
        document.getElementById('barraProgresso').style.width=d.progress+'%'; document.getElementById('txtPorcentagem').innerText=d.progress+'%'; 
        document.getElementById('txtProgresso').innerText=`Inseridos: ${d.atual - d.ignorados} de ${d.total}`; document.getElementById('txtIgnorados').innerText=`${d.ignorados} Pulados`; 
        
        const term=document.getElementById('logTerminal'); term.innerHTML=d.logs.join('<br>'); term.scrollTop=term.scrollHeight; 
        
        if(d.pausado) { document.getElementById('btnPausar').style.display='none'; document.getElementById('btnContinuar').style.display='block'; document.getElementById('iconStatus')?.classList.remove('fa-spin'); document.getElementById('textStatus').innerText='Pausado'; }
        
        if(['concluido','erro','cancelado'].includes(d.status)){
            clearInterval(monitorInterval); document.getElementById('barraProgresso').classList.remove('progress-bar-animated'); 
            document.getElementById('areaControles').style.display='none'; document.getElementById('btnNova').style.display='block'; 
            
            if(d.status!='concluido') { document.getElementById('barraProgresso').classList.add('bg-danger'); document.getElementById('textStatus').innerText = d.status.toUpperCase(); document.getElementById('iconStatus')?.classList.remove('fa-spin'); }
            else { 
                document.getElementById('textStatus').innerHTML = '<i class="fa-solid fa-check text-success me-2"></i> Concluído com Sucesso!'; 
                fetch('/gerar_relatorio/'+currentJobId).then(r=>r.json()).then(res=>{
                    document.getElementById('textoRelatorio').value = res.texto;
                    document.getElementById('areaRelatorio').style.display = 'block';
                });
            }
        } 
    }); 
}

function novaImportacao() { fetch('/limpar_sessao', {method: 'POST'}).then(() => { location.reload(); }); }
function copiarRelatorio() { const txt = document.getElementById('textoRelatorio'); txt.select(); document.execCommand('copy'); alert('✅ Copiado para a área de transferência!'); }
function enviarWhatsApp() { const txt = encodeURIComponent(document.getElementById('textoRelatorio').value); window.open(`https://api.whatsapp.com/send?text=${txt}`, '_blank'); }
</script>
{% endblock %}
EOF

# 6. Configurar Serviço (Gunicorn) em Segundo Plano
echo "[6/6] Configurando execução automática no servidor..."
cat << EOF > /etc/systemd/system/xtream_importer.service
[Unit]
Description=Xtream Importer PRO (V20)
After=network.target

[Service]
User=root
Group=www-data
WorkingDirectory=/opt/xtream_importer
Environment="PATH=/opt/xtream_importer/venv/bin"
ExecStart=/opt/xtream_importer/venv/bin/gunicorn --workers 1 --threads 10 --bind 0.0.0.0:5000 -m 007 app:app

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload > /dev/null 2>&1
systemctl enable xtream_importer > /dev/null 2>&1
systemctl restart xtream_importer > /dev/null 2>&1
ufw allow 5000/tcp > /dev/null 2>&1

IP_SERVER=$(curl -s ifconfig.me)

echo "===================================================="
echo " ✅ INSTALAÇÃO COMPLETA REALIZADA COM SUCESSO!      "
echo "===================================================="
echo " Acesse no seu navegador: http://$IP_SERVER:5000    "
echo " Usuário: admin | Senha: admin123                   "
echo "===================================================="