import os
import json
import subprocess
from flask import Flask, request, jsonify, send_file, Response

app = Flask(__name__)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))

HTML = r"""<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MKV Sub Viewer</title>
<link href="https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=Syne:wght@600;800&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
  --bg: #0d0d0f; --surface: #16161a; --border: #25252d;
  --accent: #c8ff57; --text: #e2e2ea; --muted: #55555f;
  --danger: #ff5c5c; --success: #57ffa0;
}
body {
  background: var(--bg); color: var(--text);
  font-family: 'DM Mono', monospace;
  min-height: 100vh; display: grid; grid-template-rows: auto 1fr;
}
body::before {
  content: ''; position: fixed; inset: 0;
  background: radial-gradient(ellipse 80% 50% at 50% -20%, rgba(200,255,87,.06), transparent);
  pointer-events: none;
}
header {
  padding: 24px 40px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 14px;
}
.logo { font-family: 'Syne', sans-serif; font-weight: 800; font-size: 1.1rem; color: var(--accent); }
.logo span { color: var(--text); }
main { display: grid; grid-template-columns: 300px 1fr; min-height: 0; }
.sidebar { border-right: 1px solid var(--border); padding: 24px 0; overflow-y: auto; }
.sidebar-title {
  font-family: 'Syne', sans-serif; font-size: .65rem; letter-spacing: .12em;
  color: var(--muted); text-transform: uppercase; padding: 0 20px 12px;
}
.file-list { list-style: none; }
.file-item {
  padding: 11px 20px; cursor: pointer; border-left: 2px solid transparent;
  transition: all .15s; font-size: .78rem; color: var(--muted);
  word-break: break-all; line-height: 1.4;
}
.file-item:hover { color: var(--text); background: rgba(255,255,255,.03); }
.file-item.active { color: var(--accent); border-left-color: var(--accent); background: rgba(200,255,87,.05); }
.empty { padding: 20px; font-size: .78rem; color: var(--muted); line-height: 1.6; }
.content { display: flex; flex-direction: column; padding: 32px 40px; gap: 24px; overflow-y: auto; }
.placeholder { margin: auto; text-align: center; color: var(--muted); font-size: .85rem; line-height: 2; }
.placeholder big {
  display: block; font-family: 'Syne', sans-serif; font-size: 2.5rem;
  font-weight: 800; color: var(--border); margin-bottom: 8px;
}
.section-label { font-size: .65rem; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.track-list { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.track-btn {
  background: var(--surface); border: 1px solid var(--border); color: var(--text);
  font-family: 'DM Mono', monospace; font-size: .75rem; padding: 7px 14px; cursor: pointer; transition: all .15s;
}
.track-btn:hover { border-color: var(--accent); color: var(--accent); }
.track-btn.active { background: var(--accent); color: #000; border-color: var(--accent); font-weight: 500; }
.track-btn.pt { border-color: rgba(200,255,87,.4); }
.player-wrap { background: #000; width: 100%; aspect-ratio: 16/9; }
video { width: 100%; height: 100%; display: block; }
video::cue { background: rgba(0,0,0,.85); color: #fff; font-family: 'DM Mono', monospace; font-size: 1rem; }
.actions { display: flex; gap: 10px; align-items: center; }
.btn {
  font-family: 'DM Mono', monospace; font-size: .75rem; padding: 8px 18px;
  cursor: pointer; transition: all .15s; text-decoration: none;
  display: inline-flex; align-items: center; gap: 6px;
}
.btn-outline { background: transparent; border: 1px solid var(--border); color: var(--muted); }
.btn-outline:hover { border-color: var(--text); color: var(--text); }
.status { font-size: .75rem; color: var(--muted); display: flex; align-items: center; gap: 8px; }
.dot { width: 6px; height: 6px; border-radius: 50%; background: var(--muted); }
.dot.ok { background: var(--success); box-shadow: 0 0 6px var(--success); }
.dot.loading { background: var(--accent); animation: pulse 1s infinite; }
.dot.err { background: var(--danger); }
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:.3} }
@media (max-width: 700px) {
  main { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  .sidebar { border-right: none; border-bottom: 1px solid var(--border); max-height: 200px; }
  .content { padding: 20px; }
}
</style>
</head>
<body>
<header>
  <div class="logo">mkv<span>sub</span></div>
  <span style="color:var(--muted);font-size:.75rem">— extrator de legendas local</span>
</header>
<main>
  <aside class="sidebar">
    <div class="sidebar-title">Arquivos no diretório</div>
    <ul class="file-list" id="fileList"></ul>
  </aside>
  <section class="content" id="content">
    <div class="placeholder">
      <big>▶</big>
      Selecione um arquivo<br>para ver as legendas disponíveis
    </div>
  </section>
</main>
<script>
let currentFile = null;

function saveTime(file, time) {
  if (time > 0) localStorage.setItem('mkvsub_time_' + file, time);
}

function loadTime(file) {
  return parseFloat(localStorage.getItem('mkvsub_time_' + file) || '0');
}

function startTimeTracking(player) {
  clearInterval(window._timeTracker);
  window._timeTracker = setInterval(() => {
    if (currentFile && player.currentTime > 0) {
      saveTime(currentFile, player.currentTime);
    }
  }, 2000);
}

async function init() {
  const res = await fetch('/files');
  const files = await res.json();
  const list = document.getElementById('fileList');
  if (!files.length) {
    list.innerHTML = '<li class="empty">Nenhum .mkv encontrado no diretório.</li>';
    return;
  }
  list.innerHTML = files.map(f =>
    `<li class="file-item" data-file="${f}" onclick="selectFile(this)">${f}</li>`
  ).join('');
}

async function selectFile(el) {
  document.querySelectorAll('.file-item').forEach(i => i.classList.remove('active'));
  el.classList.add('active');
  currentFile = el.dataset.file;

  setContent(`<div class="status"><div class="dot loading"></div> Lendo faixas...</div>`);

  const res = await fetch(`/tracks?file=${encodeURIComponent(currentFile)}`);
  const tracks = await res.json();

  if (!tracks.length) {
    setContent(`<div class="status"><div class="dot err"></div> Nenhuma faixa de legenda encontrada.</div>`);
    return;
  }

  const ptTracks = tracks.filter(t => ['por','pt','pt-BR','pb'].includes(t.language));

  setContent(`
    <div>
      <div class="section-label">Faixas de legenda</div>
      <div class="track-list" id="trackList">
        ${tracks.map(t => `
          <button class="track-btn${ptTracks.includes(t)?' pt':''}" data-stream="${t.index}" onclick="loadSubtitle(this,${t.index})">
            ${t.label}
          </button>`).join('')}
      </div>
      ${ptTracks.length ? `<div class="status" style="margin-top:10px"><div class="dot ok"></div> ${ptTracks.length} faixa(s) PT detectada(s)</div>` : ''}
    </div>
    <div id="playerSection" style="display:none;flex-direction:column;gap:12px">
      <div class="player-wrap"><video id="player" controls></video></div>
      <div class="actions">
        <div class="status"><div class="dot" id="subDot"></div><span id="subMsg">nenhuma legenda carregada</span></div>
        <a id="dlBtn" class="btn btn-outline" style="margin-left:auto;display:none" download>⬇ baixar .vtt</a>
      </div>
    </div>
  `);

  if (ptTracks.length) {
    const btn = document.querySelector(`[data-stream="${ptTracks[0].index}"]`);
    if (btn) loadSubtitle(btn, ptTracks[0].index);
  }
}

async function loadSubtitle(btn, streamIndex) {
  document.querySelectorAll('.track-btn').forEach(b => b.classList.remove('active'));
  btn.classList.add('active');

  const ps = document.getElementById('playerSection');
  ps.style.display = 'flex';

  document.getElementById('subDot').className = 'dot loading';
  document.getElementById('subMsg').textContent = 'extraindo via ffmpeg...';

  const player = document.getElementById('player');
  const videoUrl = `/video?file=${encodeURIComponent(currentFile)}`;
  const subUrl = `/subtitle?file=${encodeURIComponent(currentFile)}&stream=${streamIndex}`;

  // Salva posição atual antes de mexer no player
  const savedTime = player.src ? player.currentTime : loadTime(currentFile);

  player.querySelectorAll('track').forEach(t => t.remove());
  if (!player.src) player.src = videoUrl;

  // Fetch direto pra forçar extração e checar erro
  let vttText;
  try {
    const res = await fetch(subUrl);
    if (!res.ok) throw new Error(await res.text());
    vttText = await res.text();
    if (!vttText.startsWith('WEBVTT')) throw new Error('Saída inválida do ffmpeg');
  } catch (e) {
    document.getElementById('subDot').className = 'dot err';
    document.getElementById('subMsg').textContent = 'erro: ' + e.message.slice(0, 80);
    return;
  }

  // Cria blob URL pra evitar problema de CORS/cache com <track>
  const blob = new Blob([vttText], { type: 'text/vtt' });
  const blobUrl = URL.createObjectURL(blob);

  const track = document.createElement('track');
  track.kind = 'subtitles'; track.srclang = 'pt'; track.label = 'Legenda';
  track.src = blobUrl;
  track.default = true;
  player.appendChild(track);
  player.textTracks[player.textTracks.length - 1].mode = 'showing';

  // Restaura posição
  if (savedTime > 0) {
    player.addEventListener('loadedmetadata', () => {
      player.currentTime = savedTime;
    }, { once: true });
  }
  startTimeTracking(player);

  document.getElementById('subDot').className = 'dot ok';
  document.getElementById('subMsg').textContent = `stream ${streamIndex} carregado`;

  const dl = document.getElementById('dlBtn');
  dl.href = blobUrl; dl.download = `sub_stream${streamIndex}.vtt`; dl.style.display = 'inline-flex';
}

function setContent(html) { document.getElementById('content').innerHTML = html; }

init();
</script>
</body>
</html>"""


def find_mkv_files():
    return sorted(f for f in os.listdir(BASE_DIR) if f.lower().endswith('.mkv'))


def get_subtitle_tracks(filepath):
    cmd = ['ffprobe', '-v', 'quiet', '-print_format', 'json',
           '-show_streams', '-select_streams', 's', filepath]
    result = subprocess.run(cmd, capture_output=True, text=True)
    if result.returncode != 0:
        return []
    tracks = []
    for s in json.loads(result.stdout).get('streams', []):
        tags = s.get('tags', {})
        lang = tags.get('language', 'und')
        title = tags.get('title', '')
        codec = s.get('codec_name', '')
        idx = s.get('index')
        tracks.append({
            'index': idx, 'language': lang, 'title': title, 'codec': codec,
            'label': f"[{lang.upper()}] {title or codec} (stream {idx})"
        })
    return tracks


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


@app.route('/files')
def files():
    return jsonify(find_mkv_files())


@app.route('/tracks')
def tracks():
    filepath = os.path.join(BASE_DIR, request.args.get('file', ''))
    if not os.path.isfile(filepath):
        return jsonify([])
    return jsonify(get_subtitle_tracks(filepath))


@app.route('/subtitle')
def subtitle():
    filepath = os.path.join(BASE_DIR, request.args.get('file', ''))
    stream_index = request.args.get('stream', type=int)
    if not os.path.isfile(filepath) or stream_index is None:
        return 'Invalido', 400
    cmd = ['ffmpeg', '-y', '-i', filepath,
           '-map', f'0:{stream_index}', '-c:s', 'webvtt', '-f', 'webvtt', 'pipe:1']
    print(f"\n=== ffmpeg cmd: {' '.join(cmd)}")
    result = subprocess.run(cmd, capture_output=True)
    stderr = result.stderr.decode('utf-8', errors='replace')
    stdout = result.stdout.decode('utf-8', errors='replace')
    print(f"=== returncode: {result.returncode}")
    print(f"=== stderr:\n{stderr}")
    print(f"=== stdout preview:\n{stdout[:300]}")
    if result.returncode != 0:
        return stderr, 500
    return Response(stdout, mimetype='text/vtt')


@app.route('/video')
def video():
    filepath = os.path.join(BASE_DIR, request.args.get('file', ''))
    if not os.path.isfile(filepath):
        return 'Nao encontrado', 404
    size = os.path.getsize(filepath)
    range_header = request.headers.get('Range')
    if not range_header:
        return send_file(filepath, mimetype='video/x-matroska')
    m = range_header.replace('bytes=', '').split('-')
    byte1 = int(m[0])
    byte2 = int(m[1]) if m[1] else size - 1
    length = byte2 - byte1 + 1
    with open(filepath, 'rb') as f:
        f.seek(byte1)
        data = f.read(length)
    rv = Response(data, 206, mimetype='video/x-matroska', direct_passthrough=True)
    rv.headers['Content-Range'] = f'bytes {byte1}-{byte2}/{size}'
    rv.headers['Accept-Ranges'] = 'bytes'
    rv.headers['Content-Length'] = str(length)
    return rv


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

