import os
from config import get_local_db_connection
from funcs import get_duration, get_file_size_in_mb, calculate_file_hash
from tqdm import tqdm

import os, hashlib, subprocess
from config import get_local_db_connection
from concurrent.futures import ThreadPoolExecutor

THUMB_DIR          = "static/thumbnails"
THUMB_WIDTH        = 640
FF_QUALITY         = "80"

VIDEO_DIRS = [
    "U:/streamaster/",
    "E:/streamaster/streamaster/downloaded"
]

def get_all_video_files():
    files = {}
    for base in VIDEO_DIRS:
        for root, _, filenames in os.walk(base):
            for filename in filenames:
                if filename.endswith(".mp4"):
                    files[filename] = os.path.join(root, filename)
    return files

def find_video_path(filename: str):
    return all_videos[filename] if filename in all_videos else None

def mark_missing_videos(cursor, conn):
    cursor.execute("SELECT video_id, filepath FROM videos WHERE status != 'missing'")
    videos = cursor.fetchall()

    with tqdm(videos, desc="Scanning for missing videos...") as pbar:
        for vid in videos:
            pbar.update(1)
            video_id, filepath = vid.values()
            if not filepath:
                continue
            filename = os.path.basename(filepath)
            if not find_video_path(filename):
                print(f"🚫 Missing: {filename}")
                cursor.execute("UPDATE videos SET status = 'missing' WHERE video_id = %s", (video_id,))
                conn.commit()

def fill_missing_filepaths(cursor, conn):
    cursor.execute("SELECT id, filepath, status, video_id FROM videos")
    videos = cursor.fetchall()

    with tqdm(videos, desc="Updating filepaths...") as pbar:
        for vid in videos:
            pbar.update(1)

            filepath = vid['filepath']
            if not filepath:
                filename = f'{vid["video_id"]}.mp4'
            else:
                filename = os.path.basename(filepath)
    
            status = vid['status']
            
            path = find_video_path(filename)
            
            if not path:
                continue
            
            path = path.replace("\\", "/")
            if path == filepath and status != 'missing':
                continue
            
            cursor.execute("UPDATE videos SET filepath = %s, status = 'active' WHERE id = %s", (path, vid['id']))
            conn.commit()

def fill_missing_hashes(cursor, conn):
    cursor.execute("SELECT video_id, filepath FROM videos WHERE (hash IS NULL OR hash = '') AND status != 'missing'")
    videos = cursor.fetchall()

    with tqdm(videos, desc="Updating hashes...") as pbar:
        for vid in videos:
            pbar.update(1)
            video_id, filepath = vid.values()
            if filepath and os.path.exists(filepath):
                h = calculate_file_hash(filepath)
                cursor.execute("UPDATE videos SET hash = %s WHERE video_id = %s", (h, video_id))
                conn.commit()

def fill_missing_sizes(cursor, conn):
    cursor.execute("SELECT video_id, filepath FROM videos WHERE size = 0 AND status != 'missing'")
    videos = cursor.fetchall()

    with tqdm(videos, desc="Updating sizes...") as pbar:
        for vid in videos:
            pbar.update(1)
            video_id, filepath = vid.values()
            if filepath and os.path.exists(filepath):
                size = get_file_size_in_mb(filepath)
                cursor.execute("UPDATE videos SET size = %s WHERE video_id = %s", (size, video_id))
                conn.commit()

def fill_missing_durations(cursor, conn):
    cursor.execute("SELECT video_id, filepath FROM videos WHERE duration = 0 AND status != 'missing' ORDER BY size ASC")
    videos = cursor.fetchall()

    with tqdm(videos, desc="Updating durations...") as pbar:
        for vid in videos:
            pbar.update(1)
            video_id, filepath = vid.values()
            if filepath and os.path.exists(filepath):
                duration = get_duration(filepath)
                if duration <= 0:
                    print(f"🚫 Failed to get duration for {filepath}")
                    os.remove(filepath)
                    continue
                cursor.execute("UPDATE videos SET duration = %s WHERE video_id = %s", (duration, video_id))
                conn.commit()

def fill_missing_gender(cursor, conn):
    def get_data(username):
        import requests
        url = f"https://chaturbate.com/api/biocontext/{username}"
        data = requests.get(url)
        data = data.json()
        return data
    
    cursor.execute("SELECT DISTINCT username, site FROM videos WHERE gender IS NULL AND status != 'missing'")
    videos = cursor.fetchall()
    
    with tqdm(videos, desc="Updating genders...") as pbar:
        for vid in videos:
            pbar.update(1)
            username, site = vid.values()
            # try to fetch an item from videos table with the same username and site but with a non-null gender
            cursor.execute("SELECT gender FROM videos WHERE username = %s AND site = %s AND gender IS NOT NULL LIMIT 1", (username, site))
            gender = cursor.fetchone()
            if not gender:
                data = get_data(username)
                if not data:
                    continue
                if 'status' in data:
                    if data['status'] == 401:
                        continue
                gender = data['sex']
                if 'woman' in gender:
                    gender_str = 'Female'
                elif 'couple' in gender:
                    gender_str = 'Couple'
                elif 'trans' in gender:
                    gender_str = 'Trans'
                else:
                    print(f"fuck?: {gender}")
                    continue
            else:
                gender_str = gender['gender']
                
            cursor.execute("UPDATE videos SET gender = %s WHERE username = %s AND site = %s", (gender_str, username, site))
            conn.commit()
            print(f"[{cursor.rowcount}] ✅ Updated gender for {username} on {site}")

def generate_thumbnails_for_videos(cursor, conn):
    cursor.execute("SELECT video_id, filepath FROM videos WHERE status != 'missing' AND thumbnail IS NULL")
    videos = cursor.fetchall()
    
    tasks = []
    with tqdm(videos, desc="Generating thumbnails...") as pbar:
        for v in videos:
            pbar.update(1)
            video_id   = v.get("video_id")
            filepath = v.get("filepath")

            if not filepath:
                continue

            if not os.path.exists(filepath):
                continue

            thumb_path = _hashed_thumb_path(video_id)
            if not os.path.exists(thumb_path):
                tasks.append((filepath, thumb_path))

            v["thumbnail"] = thumb_path

    if tasks:
        with ThreadPoolExecutor(max_workers=os.cpu_count() * 2) as exe:
            list(exe.map(lambda t: subprocess.run(
                _gen_thumb_cmd(*t),
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL
            ), tasks))
            
        for v in videos:
            if 'thumbnail' not in v:
                continue
            v['thumbnail'] = v['thumbnail'].replace("\\", "/")
            cursor.execute("UPDATE videos SET thumbnail = %s WHERE video_id = %s", (v['thumbnail'], v['video_id']))
            conn.commit()

def _hashed_thumb_path(video_id: str):
    h = hashlib.md5(video_id.encode()).hexdigest()
    sub1, sub2 = h[:2], h[2:4]
    path = os.path.join(THUMB_DIR, sub1, sub2)
    os.makedirs(path, exist_ok=True)
    return os.path.join(path, f"{video_id}.webp")

def _gen_thumb_cmd(src: str, dest: str):
    return [
        "ffmpeg", "-y", "-loglevel", "error",
        "-ss", "0", "-i", src,
        "-vframes", "1",
        "-vf", f"thumbnail,scale={THUMB_WIDTH}:-1",
        "-q:v", FF_QUALITY,
        dest
    ]

if __name__ == '__main__':
    conn, cursor = get_local_db_connection()

    print("🔍 Scanning for missing data...")

    if True:
        all_videos = get_all_video_files()
        fill_missing_filepaths(cursor, conn)
        mark_missing_videos(cursor, conn)
        
    generate_thumbnails_for_videos(cursor, conn)
    fill_missing_sizes(cursor, conn)
    fill_missing_durations(cursor, conn)

    # fill_missing_gender(cursor, conn)
    # fill_missing_hashes(cursor, conn)
    

    cursor.close()
    conn.close()
    print("✅ All cleanup tasks completed.")