import subprocess
from pathlib import Path
from flask import Blueprint, jsonify, request, abort
import db
import extensions
from auth import login_required
from config import ALLOWED_ROOTS
from utils.youtube import yt_extract, playlist_cache as _yt_playlist_cache

bp = Blueprint('music', __name__, url_prefix='/api')

_MUSIC_EXTS = {'.mp3', '.flac', '.ogg', '.wav', '.m4a', '.aac'}
_music_playlist_cache = []


@bp.route('/music', methods=['GET'])
def get_music():
    state = db.get_state()
    return jsonify({
        'enabled':     state.get('music_enabled', '0') == '1',
        'source_type': state.get('music_source_type', 'local'),
        'source':      state.get('music_source', ''),
        'volume':      int(state.get('music_volume', '50')),
        'shuffle':     state.get('music_shuffle', '0') == '1',
        'show_overlay': state.get('music_show_overlay', '1') == '1',
        'overlay_position': state.get('music_overlay_position', 'bottom-left'),
        'now_playing': {
            'title':  state.get('music_now_title', ''),
            'artist': state.get('music_now_artist', ''),
        },
    })


@bp.route('/music', methods=['POST'])
@login_required
def set_music():
    data = request.get_json()
    if not data:
        abort(400)
    enabled     = bool(data.get('enabled', False))
    source_type = 'youtube' if data.get('source_type') == 'youtube' else 'local'
    source      = str(data.get('source', ''))
    volume      = max(0, min(100, int(data.get('volume', 50))))
    shuffle     = bool(data.get('shuffle', False))
    show_overlay     = bool(data.get('show_overlay', True))
    overlay_position = str(data.get('overlay_position', 'bottom-left'))
    if overlay_position not in {'top-left', 'top-right', 'bottom-left', 'bottom-right'}:
        overlay_position = 'bottom-left'

    db.set_state('music_enabled',          '1' if enabled else '0')
    db.set_state('music_source_type',      source_type)
    db.set_state('music_source',           source)
    db.set_state('music_volume',           str(volume))
    db.set_state('music_shuffle',          '1' if shuffle else '0')
    db.set_state('music_show_overlay',     '1' if show_overlay else '0')
    db.set_state('music_overlay_position', overlay_position)

    payload = {
        'enabled': enabled, 'source_type': source_type,
        'source': source, 'volume': volume, 'shuffle': shuffle,
        'show_overlay': show_overlay, 'overlay_position': overlay_position,
    }
    extensions.socketio.emit('music_settings', payload)
    return '', 204


@bp.route('/music/tracks', methods=['GET'])
@login_required
def get_music_tracks():
    folder = request.args.get('path', '')
    if not folder:
        return jsonify([])
    p = Path(folder)
    try:
        p = p.resolve()
        if not any(str(p).startswith(str(r)) for r in ALLOWED_ROOTS):
            abort(403)
    except Exception:
        abort(400)
    if not p.is_dir():
        return jsonify([])
    tracks = sorted([
        {'name': f.name, 'path': str(f)}
        for f in p.iterdir()
        if f.is_file() and f.suffix.lower() in _MUSIC_EXTS
    ], key=lambda x: x['name'])
    return jsonify(tracks)


@bp.route('/music/extract', methods=['POST'])
@login_required
def extract_music_playlist():
    """Extract video IDs for the music playlist and persist to DB."""
    global _music_playlist_cache
    data = request.get_json() or {}
    url  = str(data.get('url', '')).strip()
    if not url:
        return jsonify({'error': 'URL saknas'}), 400
    try:
        ids, _total_seconds = yt_extract(url)
    except subprocess.TimeoutExpired:
        return jsonify({'error': 'Timeout — spellistans hämtning tog för lång tid'}), 504
    except Exception as e:
        return jsonify({'error': str(e)}), 500

    _music_playlist_cache = ids
    _yt_playlist_cache[url] = ids
    db.set_state('music_playlist_ids', ','.join(ids))
    return jsonify({'count': len(ids), 'ids': ids})


@bp.route('/music/playlist', methods=['GET'])
def get_music_playlist():
    """Return the extracted playlist video IDs."""
    global _music_playlist_cache
    if not _music_playlist_cache:
        stored = db.get_state().get('music_playlist_ids', '')
        _music_playlist_cache = [v for v in stored.split(',') if v] if stored else []
    return jsonify({'ids': _music_playlist_cache, 'count': len(_music_playlist_cache)})


@bp.route('/music/nowplaying', methods=['POST'])
def update_now_playing():
    """Called by display client to broadcast now-playing state to admin."""
    data   = request.get_json() or {}
    title  = str(data.get('title',  ''))[:200]
    artist = str(data.get('artist', ''))[:200]
    db.set_state('music_now_title',  title)
    db.set_state('music_now_artist', artist)
    extensions.socketio.emit('now_playing', {'title': title, 'artist': artist})
    return '', 204


# --- YouTube playlist extraction (video & musik) ---

def _playlist_db_key(url):
    import hashlib
    return 'playlist_ids_' + hashlib.md5(url.encode()).hexdigest()


@bp.route('/playlist/extract', methods=['POST'])
@login_required
def extract_playlist():
    """Extract video IDs from any public YouTube playlist URL and cache by URL."""
    data = request.get_json() or {}
    url  = str(data.get('url', '')).strip()
    if not url:
        return jsonify({'error': 'URL saknas'}), 400
    try:
        ids, total_seconds = yt_extract(url)
    except subprocess.TimeoutExpired:
        return jsonify({'error': 'Timeout'}), 504
    except Exception as e:
        return jsonify({'error': str(e)}), 500
    _yt_playlist_cache[url] = ids
    db.set_state(_playlist_db_key(url), ','.join(ids))
    return jsonify({'count': len(ids), 'ids': ids, 'total_seconds': total_seconds})


@bp.route('/playlist/ids', methods=['GET'])
def get_playlist_ids():
    """Return cached video IDs for a playlist URL (memory cache, then DB)."""
    url = request.args.get('url', '').strip()
    ids = _yt_playlist_cache.get(url)
    if not ids:
        stored = db.get_state().get(_playlist_db_key(url), '')
        ids = [v for v in stored.split(',') if v] if stored else []
        if ids:
            _yt_playlist_cache[url] = ids
    return jsonify({'ids': ids or [], 'count': len(ids or [])})
