from flask import Flask, Response, jsonify, render_template, request, redirect, url_for, session, flash
from app import app, db, functions, sp, jellyfin, celery, jellyfin_admin_token, jellyfin_admin_id,device_id,  cache
from app.models import JellyfinUser,Playlist,Track
from celery.result import AsyncResult
from .version import __version__

@app.context_processor
def add_context():
    unlinked_track_count = len(Track.query.filter_by(downloaded=True,jellyfin_id=None).all())
    version = f"v{__version__}"
    return dict(unlinked_track_count = unlinked_track_count, version = version)

@app.after_request
def render_messages(response: Response) -> Response:
    if request.headers.get("HX-Request"):
        messages = render_template("partials/alerts.jinja2")
        response.headers['HX-Trigger'] = 'showToastMessages'
        response.data = response.data + messages.encode("utf-8")
    return response



@app.route('/admin/tasks')
@functions.jellyfin_admin_required
def task_manager():
    statuses = {}
    for task_name, task_id in functions.TASK_STATUS.items():
        if task_id:
            result = AsyncResult(task_id)
            statuses[task_name] = {'state': result.state, 'info': result.info if result.info else {}}
        else:
            statuses[task_name] = {'state': 'NOT STARTED', 'info': {}}
    
    return render_template('admin/tasks.html', tasks=statuses)

@app.route('/admin')
@app.route('/admin/link_issues')
@functions.jellyfin_admin_required
def link_issues():
    unlinked_tracks = Track.query.filter_by(downloaded=True,jellyfin_id=None).all()
    tracks = []
    for ult in unlinked_tracks: 
        sp_track = functions.get_cached_spotify_track(ult.spotify_track_id)
        duration_ms = sp_track['duration_ms']
        minutes = duration_ms // 60000
        seconds = (duration_ms % 60000) // 1000
        tracks.append({
                'title': sp_track['name'],
                'artist': ', '.join([artist['name'] for artist in sp_track['artists']]),
                'url': sp_track['external_urls']['spotify'],
                'duration': f'{minutes}:{seconds:02d}', 
                'preview_url': sp_track['preview_url'],
                'downloaded': ult.downloaded,  
                'filesystem_path': ult.filesystem_path,  
                'jellyfin_id': ult.jellyfin_id,
                'spotify_id': sp_track['id'],
                'duration_ms': duration_ms,
                'download_status'  : ult.download_status
            })

    return render_template('admin/link_issues.html' , tracks = tracks )



@app.route('/run_task/<task_name>', methods=['POST'])
@functions.jellyfin_admin_required
def run_task(task_name):
    status, info = functions.manage_task(task_name)
    
    # Rendere nur die aktualisierte Zeile der Task
    task_info = {task_name: {'state': status, 'info': info}}
    return render_template('partials/_task_status.html', tasks=task_info)


@app.route('/task_status')
@functions.jellyfin_admin_required
def task_status():
    statuses = {}
    for task_name, task_id in functions.TASK_STATUS.items():
        if task_id:
            result = AsyncResult(task_id)
            statuses[task_name] = {'state': result.state, 'info': result.info if result.info else {}}
        else:
            statuses[task_name] = {'state': 'NOT STARTED', 'info': {}}

    # Render the HTML partial template instead of returning JSON
    return render_template('partials/_task_status.html', tasks=statuses)



@app.route('/')
@functions.jellyfin_login_required 
def index():
    users = JellyfinUser.query.all()
    return render_template('index.html', user=session['jellyfin_user_name'], users=users)

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        try:
            jellylogin = jellyfin.login_with_password(username=username, password=password)
            if jellylogin:
                session['jellyfin_access_token'], session['jellyfin_user_id'], session['jellyfin_user_name'],session['is_admin'] = jellylogin
                session['debug'] = app.debug
                # Check if the user already exists
                user = JellyfinUser.query.filter_by(jellyfin_user_id=session['jellyfin_user_id']).first()
                if not user:
                    # Add the user to the database if they don't exist
                    new_user = JellyfinUser(name=session['jellyfin_user_name'], jellyfin_user_id=session['jellyfin_user_id'], is_admin = session['is_admin'])
                    db.session.add(new_user)
                    db.session.commit()

                return redirect('/playlists')
        except:
            flash('Login failed. Please check your Jellyfin credentials and try again.', 'error')
            return redirect(url_for('login'))

    return render_template('login.html')

@app.route('/logout')
def logout():
    session.pop('jellyfin_user_name', None)
    session.pop('jellyfin_access_token', None)
    return redirect(url_for('login'))


@app.route('/playlists')
@app.route('/categories')
@app.route('/playlists/monitored')
@functions.jellyfin_login_required
def loaditems():
    country = 'DE'
    offset = int(request.args.get('offset', 0))  # Get the offset (default to 0 for initial load)
    limit = 20  # Define a limit for pagination
    additional_query = ''
    items_subtitle = ''

    if request.path == '/playlists/monitored':
        # Step 1: Query the database for monitored playlists
        db_playlists = db.session.query(Playlist).offset(offset).limit(limit).all()
        max_items = db.session.query(Playlist).count()
        
        # Collect Spotify Playlist IDs from the database
        spotify_playlist_ids = [playlist.spotify_playlist_id for playlist in db_playlists]
      
        spotify_data = functions.get_cached_spotify_playlists(tuple(spotify_playlist_ids))

        # Step 3: Pass the Spotify data to prepPlaylistData for processing
        data = functions.prepPlaylistData(spotify_data)
        items_title = "Monitored Playlists"
        items_subtitle = "This playlists are already monitored by the Server, if you add one of these to your Jellyfin account, they will be available immediately."

    elif request.path == '/playlists':
        cat = request.args.get('cat', None)
        if cat is not None:
            data, max_items, items_title = functions.getCategoryPlaylists(category=cat, offset=offset)
            additional_query += f"&cat={cat}"
        else:
            data, max_items, items_title = functions.getFeaturedPlaylists(country=country, offset=offset)

    elif request.path == '/categories':
        data, max_items, items_title = functions.getCategories(country=country, offset=offset)

    next_offset = offset + len(data)
    total_items = max_items
    context = {
        'items': data,
        'next_offset': next_offset,
        'total_items': total_items,
        'endpoint': request.path,
        'items_title': items_title,
        'items_subtitle' : items_subtitle,
        'additional_query': additional_query
    }

    if request.headers.get('HX-Request'):  # Check if the request is from HTMX
        return render_template('partials/_spotify_items.html', **context)
    else:
        return render_template('items.html', **context)


@app.route('/search')
@functions.jellyfin_login_required
def searchResults():
    query = request.args.get('query')
    context = {}
    if query:
        # Add your logic here to perform the search on Spotify (or Jellyfin)
        search_result = sp.search(q = query, type= 'track,album,artist,playlist')
        context = {
            'artists' : functions.prepArtistData(search_result ),
            'playlists' : functions.prepPlaylistData(search_result ),
            'albums' : functions.prepAlbumData(search_result ),
            'query' : query
        }
        return render_template('search.html', **context)
    else:
        return render_template('search.html', query=None, results={})


@app.route('/playlist/view/<playlist_id>')
@functions.jellyfin_login_required
def get_playlist_tracks(playlist_id):
    # Hol dir alle Tracks für die Playlist
    data = functions.get_full_playlist_data(playlist_id)  # Diese neue Funktion holt alle Tracks der Playlist
    tracks = functions.get_tracks_for_playlist(data)  # Deine Funktion, um Tracks zu holen
    # Berechne die gesamte Dauer der Playlist
    total_duration_ms = sum([track['track']['duration_ms'] for track in data['tracks'] if track['track']])

    # Konvertiere die Gesamtdauer in ein lesbares Format
    hours, remainder = divmod(total_duration_ms // 1000, 3600)
    minutes, seconds = divmod(remainder, 60)

    # Formatierung der Dauer
    if hours > 0:
        total_duration = f"{hours}h {minutes}min"
    else:
        total_duration = f"{minutes}min"
    
    return render_template(
        'tracks_table.html',
        tracks=tracks,
        total_duration=total_duration,
        track_count=len(data['tracks']),
        playlist_name=data['name'],
        playlist_cover=data['images'][0]['url'],
        playlist_description=data['description'],
        last_updated = data['prepped_data'][0]['last_updated'],
        last_changed = data['prepped_data'][0]['last_changed'],
        item = data['prepped_data'][0],
        
    )
@app.route('/associate_track', methods=['POST'])
@functions.jellyfin_login_required
def associate_track():
    jellyfin_id = request.form.get('jellyfin_id')
    spotify_id = request.form.get('spotify_id')

    if not jellyfin_id or not spotify_id:
        flash('Missing Jellyfin or Spotify ID')

    # Retrieve the track by Spotify ID
    track = Track.query.filter_by(spotify_track_id=spotify_id).first()

    if not track:
        flash('Track not found')
        return ''

    # Associate the Jellyfin ID with the track
    track.jellyfin_id = jellyfin_id

    try:
        # Commit the changes to the database
        db.session.commit()
        flash("Track associated","success")
        return ''
    except Exception as e:
        db.session.rollback()  # Roll back the session in case of an error
        flash(str(e))
        return ''
        

@app.route('/test')
def test():
    return ''