import os
import re
import html
import logging
import requests
import yt_dlp
from fastapi import FastAPI, Request, Form
from fastapi.responses import HTMLResponse, JSONResponse, FileResponse, Response
from fastapi.templating import Jinja2Templates

# --- Logging Configuration ---
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

app = FastAPI(title="Tubeify Web Downloader")

templates = Jinja2Templates(directory="templates")

os.makedirs('downloads', exist_ok=True)
COOKIES_FILE = "cookies.txt"

def youtube_bypass_opts():
    opts = {
        'source_address': '0.0.0.0',
        'extractor_args': {'youtube': {'player_client': ['android', 'ios', 'web']}},
        'retries': 3,
        'socket_timeout': 20,
        'geo_bypass': True,
        'nocheckcertificate': True,
        'noplaylist': True,
    }
    if os.path.exists(COOKIES_FILE):
        opts['cookiefile'] = COOKIES_FILE
    return opts

def format_number(num):
    if not num:
        return "N/A"
    try:
        num = int(num)
        if num >= 1_000_000:
            return f"{num / 1_000_000:.1f}M"
        elif num >= 1_000:
            return f"{num / 1_000:.1f}K"
        return str(num)
    except Exception:
        return "N/A"

def get_spotify_meta(url):
    try:
        cover = None
        try:
            oembed_res = requests.get("https://open.spotify.com/oembed", params={'url': url}, timeout=8)
            if oembed_res.status_code == 200:
                cover = oembed_res.json().get('thumbnail_url')
        except:
            pass

        headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'}
        page_res = requests.get(url, headers=headers, timeout=8)
        if page_res.status_code != 200:
            return None

        title_match = re.search(r'<title>(.*?)</title>', page_res.text, re.IGNORECASE | re.DOTALL)
        if not title_match:
            return None

        raw_title = html.unescape(title_match.group(1)).replace(" | Spotify", "").strip()
        if " - song and lyrics by " in raw_title:
            title, artist = raw_title.split(" - song and lyrics by ", 1)
        elif " - song by " in raw_title:
            title, artist = raw_title.split(" - song by ", 1)
        elif " - " in raw_title:
            artist, title = raw_title.split(" - ", 1)
        else:
            title, artist = raw_title, "Unknown Artist"

        return {'title': title.strip(), 'artist': artist.strip(), 'cover': cover}
    except Exception as e:
        logger.error(f"Spotify meta error: {e}")
    return None

def get_apple_music_meta(url):
    try:
        res = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'}, timeout=8)
        if res.status_code == 200:
            title_match = re.search(r'<meta property="og:title" content="(.*?)"', res.text)
            cover_match = re.search(r'<meta property="og:image" content="(.*?)"', res.text)
            title_full = html.unescape(title_match.group(1)) if title_match else "Apple Music Track"

            parts = title_full.split(" - Single by ") if " - Single by " in title_full else title_full.split(" by ")
            title = parts[0]
            artist = parts[1] if len(parts) > 1 else "Unknown Artist"

            return {'title': title.strip(), 'artist': artist.strip(), 'cover': cover_match.group(1) if cover_match else None}
    except Exception as e:
        logger.error(f"Apple meta error: {e}")
    return None

@app.get("/logo.webp")
async def get_logo():
    return FileResponse("templates/logo.webp")

@app.get("/sitemap.xml", include_in_schema=False)
async def sitemap():
    sitemap_content = """<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://tubeify.ir/</loc>
    <changefreq>daily</changefreq>
    <priority>1.0</priority>
  </url>
</urlset>"""
    return Response(content=sitemap_content, media_type="application/xml")

@app.get("/robots.txt", include_in_schema=False)
async def robots_txt():
    if os.path.exists("robots.txt"):
        return FileResponse("robots.txt")
    return Response("User-agent: *\nAllow: /\n\nSitemap: https://tubeify.ir/sitemap.xml", media_type="text/plain")

@app.get("/", response_class=HTMLResponse)
async def home(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

@app.post("/api/fetch")
async def fetch_media(url: str = Form(...)):
    url = url.strip()
    if not url.startswith("http"):
        return JSONResponse({"success": False, "error": "لطفاً یک لینک معتبر وارد کنید."})

    platform = "Media"
    if "spotify.com" in url: platform = "Spotify"
    elif "music.apple.com" in url: platform = "AppleMusic"
    elif "instagram.com" in url: platform = "Instagram"
    elif "tiktok.com" in url: platform = "TikTok"
    elif "youtube.com" in url or "youtu.be" in url: 
        platform = "YouTube"
        url = url.split('&list=')[0].split('?list=')[0].split('&index=')[0]

    try:
        target_url = url
        title = "Media Content"
        uploader = "Unknown"
        views = "N/A"
        thumbnail = None

        if platform == "Spotify":
            meta = get_spotify_meta(url)
            if not meta: return JSONResponse({"success": False, "error": "یافتن آهنگ اسپاتیفای با خطا مواجه شد."})
            target_url = f"ytsearch1:{meta['artist']} - {meta['title']} audio"
            title, uploader, thumbnail = meta['title'], meta['artist'], meta['cover']
        elif platform == "AppleMusic":
            meta = get_apple_music_meta(url)
            if not meta: return JSONResponse({"success": False, "error": "خطا در دریافت اطلاعات اپل موزیک."})
            target_url = f"ytsearch1:{meta['artist']} - {meta['title']} audio"
            title, uploader, thumbnail = meta['title'], meta['artist'], meta['cover']

        ydl_opts_info = {'quiet': True, 'no_warnings': True, **youtube_bypass_opts()}
        with yt_dlp.YoutubeDL(ydl_opts_info) as ydl:
            info = ydl.extract_info(target_url, download=False)
            
            if 'entries' in info and len(info['entries']) > 0:
                info = info['entries'][0]

            if platform not in ["Spotify", "AppleMusic"]:
                title = info.get('title', title)
                uploader = info.get('uploader', info.get('channel', uploader))
                views = format_number(info.get('view_count', 0))
                thumbnail = info.get('thumbnail', thumbnail)

            formats_list = []

            if platform in ["Spotify", "AppleMusic"]:
                best_audio = info.get('url')
                for f in info.get('formats', []):
                    if f.get('acodec') != 'none' and f.get('vcodec') == 'none':
                        best_audio = f.get('url')
                formats_list.append({'resolution': 'دانلود صوتی (Audio MP3)', 'url': best_audio, 'type': 'audio'})

            elif platform in ["Instagram", "TikTok"]:
                vid_url = info.get('url')
                if not vid_url and info.get('formats'):
                    vid_url = info['formats'][-1].get('url')
                formats_list.append({'resolution': 'دانلود ویدیو با کیفیت اصلی', 'url': vid_url, 'type': 'video'})

            else:
                seen_res = set()
                best_audio = None
                
                for f in info.get('formats', []):
                    h = f.get('height')
                    f_url = f.get('url')
                    if h and f_url and h >= 144:
                        if h not in seen_res:
                            seen_res.add(h)
                            formats_list.append({
                                'resolution': f"{h}p (ویدیو)", 
                                'url': f_url, 
                                'type': 'video'
                            })

                formats_list.sort(key=lambda x: int(x['resolution'].split('p')[0]), reverse=True)

                for f in info.get('formats', []):
                    if f.get('acodec') != 'none' and f.get('vcodec') == 'none':
                        best_audio = f.get('url')
                        break

                if not best_audio:
                    best_audio = info.get('url')

                formats_list.append({
                    'resolution': 'دانلود صوتی (Audio MP3)', 
                    'url': best_audio, 
                    'type': 'audio'
                })

        return JSONResponse({
            "success": True,
            "platform": platform,
            "title": title,
            "uploader": uploader,
            "views": views,
            "thumbnail": thumbnail,
            "formats": formats_list
        })

    except Exception as e:
        logger.error(f"Web extraction error: {e}")
        return JSONResponse({"success": False, "error": "ارتباط با سرور دانلود ناموفق بود، لینک خصوصی است یا پشتیبانی نمی‌شود."})