#!/usr/bin/env python3
"""Background update script for M3U and EPG with progress tracking."""
import sys, os, json, time
from datetime import datetime

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

def write_progress(phase, message, percent=0, total=0, processed=0, added=0, updated=0, removed=0, error=None, running=True):
    data = {
        'running': running,
        'phase': phase,
        'message': message,
        'percent': int(percent),
        'total': total,
        'processed': processed,
        'added': added,
        'updated': updated,
        'removed': removed,
        'new': added,
        'error': error,
        'timestamp': datetime.now().isoformat(),
    }
    try:
        with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'progress_m3u.json'), 'w') as f:
            json.dump(data, f)
    except Exception:
        pass

def write_xtream_progress(phase, message, percent=0, total=0, processed=0, added=0, updated=0, error=None, running=True):
    data = {
        'running': running,
        'phase': phase,
        'message': message,
        'percent': int(percent),
        'total': total,
        'processed': processed,
        'added': added,
        'updated': updated,
        'error': error,
        'timestamp': datetime.now().isoformat(),
    }
    try:
        with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'progress_xtream.json'), 'w') as f:
            json.dump(data, f)
    except Exception:
        pass

def is_cancelled():
    try:
        pf = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'progress_m3u.json')
        if os.path.exists(pf):
            with open(pf, 'r') as f:
                data = json.load(f)
            return data.get('cancelled', False)
    except Exception:
        pass
    return False

def mark_cancelled():
    try:
        pf = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'progress_m3u.json')
        data = {}
        if os.path.exists(pf):
            with open(pf, 'r') as f:
                data = json.load(f)
        data['cancelled'] = True
        with open(pf, 'w') as f:
            json.dump(data, f)
    except Exception:
        pass

def _record_cron_run(nome):
    try:
        from app import _record_cron_run as registrar
        registrar(nome)
    except Exception:
        pass


def stage_progress(etapa, pct, msg):
    """Callback da fila completa: publica cada etapa no painel."""
    running = etapa != 'done'
    if not running:
        write_progress('done', msg or 'Atualizacao concluida', 100, running=False)
    else:
        write_progress(etapa, msg, pct, running=True)


def should_stop():
    return is_cancelled()


def run_full_update():
    """M3U + EPG + Xtream na mesma fila (botao do painel e cron)."""
    from app import run_catalog_update
    write_progress('init', 'Iniciando atualizacao completa do catalogo (M3U, EPG, Xtream)...', 1)
    print(f'[{datetime.now()}] BG: Iniciando fila completa (m3u + epg + xtream)...', flush=True)
    if is_cancelled():
        write_progress('cancelled', 'Atualizacao cancelada antes de comecar.', 0, running=False)
        return
    try:
        resumo = run_catalog_update(progress=stage_progress, should_stop=should_stop)
        erros = resumo.get('errors') or []
        if resumo.get('cancelled'):
            write_progress('cancelled', 'Atualizacao cancelada pelo painel.', 0, running=False)
        elif erros:
            write_progress('partial', 'Atualizacao parcial: ' + '; '.join(
                f"{e.get('stage')}: {e.get('error')}" for e in erros), 100,
                running=False, error=str(erros))
        else:
            m3u = resumo.get('results', {}).get('m3u', {})
            epg = resumo.get('results', {}).get('epg', {})
            xt = resumo.get('results', {}).get('xtream', {})
            write_progress('done',
                           f'Catalogo completo: +{m3u.get("added", 0)}, ~{m3u.get("updated", 0)}, '
                           f'-{m3u.get("removed", 0)} (total {m3u.get("total", 0)}); '
                           f'EPG {epg.get("programs", 0)} programas / {epg.get("mapped", 0)} canais; '
                           f'Xtream {xt.get("movies", 0)} filmes / {xt.get("series", 0)} series.',
                           100, total=m3u.get('total', 0), processed=m3u.get('total', 0),
                           added=m3u.get('added', 0), updated=m3u.get('updated', 0),
                           removed=m3u.get('removed', 0), running=False)
        print(f'[{datetime.now()}] BG: Fila completa finalizada: {resumo}', flush=True)
        return resumo
    except Exception as e:
        write_progress('error', f'Erro: {e}', 0, error=str(e), running=False)
        print(f'[{datetime.now()}] BG: Erro na fila completa: {e}', flush=True)


def run_m3u_update():
    """Nome antigo do fluxo: hoje atualiza M3U + EPG + Xtream."""
    return run_full_update()

def run_m3u_import():
    """Importa o arquivo M3U ja enviado pelo painel e segue com EPG + Xtream."""
    from app import (app, db, import_m3u_full_sync, repair_existing_catalog_metadata,
                     _validate_m3u_file, M3U_PATH, Canal, invalidate_cache,
                     M3USourceLog, run_catalog_update)
    write_progress('validate', 'Validando arquivo M3U enviado...', 5)
    try:
        print(f'[{datetime.now()}] BG: Importando M3U enviada manualmente...', flush=True)
        with app.app_context():
            stats = _validate_m3u_file(M3U_PATH)
            print(f'[{datetime.now()}] BG: arquivo valido: {stats}', flush=True)
            result = import_m3u_full_sync(M3U_PATH)
            repaired = repair_existing_catalog_metadata()
            total = Canal.query.count()
            M3USourceLog.log(
                None, 'arquivo enviado', 'sync', 'ok',
                f'Import M3U (arquivo): +{result.get("added", 0)} novos, '
                f'~{result.get("updated", 0)} atualizados, -{result.get("removed", 0)} removidos, '
                f'saneados {repaired}. Total: {total}.',
                details={'added': result.get('added', 0), 'updated': result.get('updated', 0),
                         'removed': result.get('removed', 0), 'repaired': repaired, 'total': total}
            )
            invalidate_cache('canais:')
            invalidate_cache('filmes:')
            invalidate_cache('series:')
            invalidate_cache('landing:')
            invalidate_cache('admin:')
        print(f'[{datetime.now()}] BG: M3U manual finalizada: {result} saneados={repaired}', flush=True)
        _record_cron_run('update-m3u')
        # A fila continua com o guia e os metadados: o upload de um arquivo nao
        # pode deixar a grade e as capas desatualizados.
        run_catalog_update(stages=('epg', 'xtream'), progress=stage_progress,
                           should_stop=should_stop)
    except Exception as e:
        write_progress('error', f'Erro: {e}', 0, error=str(e), running=False)
        try:
            M3USourceLog.log(None, 'arquivo enviado', 'sync', 'error',
                             f'Import M3U (arquivo) falhou: {e}', details={'error': str(e)})
        except Exception:
            pass
        print(f'[{datetime.now()}] BG: Erro M3U manual: {e}', flush=True)


def run_epg_update():
    from app import app, update_epg, M3USourceLog
    write_progress('download', 'Baixando EPG...', 10)
    try:
        print(f'[{datetime.now()}] BG: Iniciando atualizacao EPG...', flush=True)
        result = update_epg()
        channels = result.get('channels', 0)
        programs = result.get('programs', 0)
        mapped = result.get('mapped', 0)
        write_progress('done', f'EPG atualizado: {channels} canais, {programs} programas, {mapped} mapeados.',
                       100, total=programs, processed=programs, added=programs, running=False)
        try:
            M3USourceLog.log(None, 'EPG', 'sync', 'ok',
                             f'EPG atualizado: {channels} canais, {programs} programas, {mapped} mapeados.',
                             details={'channels': channels, 'programs': programs, 'mapped': mapped})
        except Exception:
            pass
        _record_cron_run('update-epg')
        print(f'[{datetime.now()}] BG: EPG finalizado: {result}', flush=True)
    except Exception as e:
        write_progress('error', f'Erro EPG: {e}', 0, error=str(e), running=False)
        try:
            M3USourceLog.log(None, 'EPG', 'sync', 'error', f'EPG falhou: {e}', details={'error': str(e)})
        except Exception:
            pass
        print(f'[{datetime.now()}] BG: Erro EPG: {e}', flush=True)

def run_xtream_enrich():
    from app import app, enrich_xtream_metadata
    write_xtream_progress('init', 'Iniciando enriquecimento Xtream...', 10)
    try:
        print(f'[{datetime.now()}] BG: Iniciando enriquecimento Xtream...', flush=True)
        result = enrich_xtream_metadata(batch_size=30, max_items=0)
        if result.get('success'):
            capas = result.get('capas') or {}
            detalhe = ''
            if capas.get('total_series'):
                detalhe = ' (capa oficial em %s de %s series)' % (
                    capas.get('cobertas', 0), capas.get('total_series'))
            write_xtream_progress('done', f'Enriquecimento concluido: {result.get("movies", 0)} filmes, {result.get("series", 0)} series{detalhe}.',
                           100, added=result.get('movies', 0), updated=result.get('series', 0), running=False)
        else:
            write_xtream_progress('error', f'Erro: {result.get("message", "Unknown")}', 0, error=result.get("message", "Unknown"), running=False)
        _record_cron_run('xtream-enrich')
        print(f'[{datetime.now()}] BG: Xtream enrich finalizado: {result}', flush=True)
    except Exception as e:
        write_xtream_progress('error', f'Erro: {e}', 0, error=str(e), running=False)
        print(f'[{datetime.now()}] BG: Erro Xtream enrich: {e}', flush=True)

if __name__ == '__main__':
    # Import migration check
    from app import app
    with app.app_context():
        from app import db
        try:
            db.create_all()
        except Exception:
            pass

    mode = sys.argv[1] if len(sys.argv) > 1 else 'all'
    mark_cancelled()
    if mode == 'epg':
        run_epg_update()
    elif mode == 'xtream':
        run_xtream_enrich()
    elif mode == 'm3u_import':
        run_m3u_import()
    elif mode in ('all', 'm3u'):
        # 'm3u' continua valendo: hoje a atualizacao da lista puxa tambem EPG e Xtream
        run_full_update()
    else:
        run_full_update()
