import os
import datetime
import io
import zipfile
import requests
from flask import Flask, render_template, request, send_file, after_this_request
from pytubefix import YouTube
from pytubefix.exceptions import VideoUnavailable
from werkzeug.utils import secure_filename
from moviepy.editor import AudioFileClip

app = Flask(__name__)
# Flask secret key
app.config['SECRET_KEY'] = 'your-secret-key-here'
# Cloudflare Turnstile secret key
TURNSTILE_SECRET_KEY = '0x4AAAAAABN5AJIcyCnb-wPGulIsFw6Jpes'

# Ensure download folder
download_dir = 'downloads'
os.makedirs(download_dir, exist_ok=True)


def log_download(yt_title, file_format, file_path):
    """Append a log entry with timestamp, title, format, and path."""
    now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    with open('log.txt', 'a') as f:
        f.write(f"{now} - Title: {yt_title}, Format: {file_format}, Filepath: {file_path}\n")


@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        # verify Cloudflare captcha
        captcha = request.form.get('cf-turnstile-response')
        if not captcha:
            return render_template('index.html', error='Captcha verification failed.')

        verify = requests.post(
            'https://challenges.cloudflare.com/turnstile/v0/siteverify',
            data={'secret': TURNSTILE_SECRET_KEY,
                  'response': captcha,
                  'remoteip': request.remote_addr}
        )
        if not verify.json().get('success'):
            return render_template('index.html', error='Captcha verification failed.')

        # determine mode
        bulk = bool(request.form.get('bulk_process'))
        fmt = request.form.get('format', 'mp4')
        quality = request.form.get('quality')
        urls = []
        if bulk:
            raw = request.form.get('url_bulk', '').splitlines()
            urls = [u.strip() for u in raw if u.strip()]
        else:
            single = request.form.get('url', '').strip()
            urls = [single]

        # prepare archive for bulk
        zip_buffer = io.BytesIO() if bulk else None
        if zip_buffer:
            zipf = zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED)

        for url in urls:
            try:
                yt = YouTube(url, use_oauth=True, allow_oauth_cache=True)
                if fmt == 'mp3':
                    stream = yt.streams.filter(only_audio=True).order_by('abr').desc().first()
                    path = stream.download(output_path=download_dir)
                    mp3 = os.path.splitext(path)[0] + '.mp3'
                    AudioFileClip(path).write_audiofile(mp3)
                    log_download(yt.title, 'mp3', mp3)
                    file_path = mp3
                else:
                    streams = yt.streams.filter(progressive=True,
                                                 file_extension='mp4')
                    # no 'best' option: only selected resolution
                    stream = streams.get_by_resolution(quality) or streams.order_by('resolution').desc().first()
                    path = stream.download(output_path=download_dir)
                    log_download(yt.title, 'mp4', path)
                    file_path = path
                # add to zip or yield
                if bulk:
                    arc_name = os.path.basename(file_path)
                    zipf.write(file_path, arc_name)
                else:
                    @after_this_request
                    def cleanup(response):
                        try:
                            os.remove(file_path)
                        except:
                            pass
                        return response
                    # single file send
                    return send_file(
                        file_path,
                        as_attachment=True,
                        download_name=secure_filename(os.path.basename(file_path)),
                        mimetype='audio/mpeg' if fmt=='mp3' else 'video/mp4'
                    )

            except VideoUnavailable:
                return render_template('index.html', error=f'Video unavailable: {url}')

        # finish bulk: close zip and send
        zipf.close()
        zip_buffer.seek(0)
        @after_this_request
        def cleanup_all(response):
            try:
                for fpath in os.listdir(download_dir):
                    os.remove(os.path.join(download_dir, fpath))
            except:
                pass
            return response

        ts = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
        zip_name = f'bulk_{ts}.zip'
        return send_file(
            zip_buffer,
            as_attachment=True,
            download_name=zip_name,
            mimetype='application/zip'
        )

    # GET
    return render_template('index.html')


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
