from flask import Flask, request, current_app
import logging
import os
from datetime import datetime, timedelta
import re

from playhouse.shortcuts import model_to_dict, dict_to_model
from peewee import fn

from pymrf4.utils import object_to_dict
from pymrf4.models import Torrent, Announce

from pymrf4.harvestor import Harvestor

# Tells Flask that you're in a subprocess, don't handle Ctrl+C event
os.environ["WERKZEUG_RUN_MAIN"] = "False"

app = Flask(__name__, static_url_path='', static_folder="web/static")

logger = logging.getLogger('werkzeug')
logger.setLevel(logging.ERROR)


@app.route("/api/get-recent-torrents")
def get_recent_torrents():
    torrents = list(Torrent.select()
                    .where(Torrent.last_announced_at >= (datetime.now() - timedelta(days=1)))
                    .dicts())

    return torrents

@app.route("/api/get-announces/<id>")
def get_announces(id):
    return list(Announce.select().where(Announce.torrent_id == id).order_by(Announce.created_at.desc()).limit(10).dicts())


@app.route("/api/get-last-announces")
def get_last_announces():
    active_torrent_ids = list(Torrent.select(Torrent.id).where(Torrent.last_event != "stopped").dicts())
    active_torrent_ids = [t['id'] for t in active_torrent_ids]
    latest_announces = Announce.select(fn.Max(Announce.created_at), Announce.upload_speed, Announce.torrent_id) \
        .where(Announce.torrent_id.in_(active_torrent_ids) & (Announce.created_at > datetime.now() - timedelta(minutes=6))) \
        .group_by(Announce.torrent_id).dicts()
    return list(latest_announces)


@app.route("/api/get-harvestor-status")
def get_harvestor_status():
    # NOTE: "queue is empty" doesn't mean the harvestor is stopped,
    # because workers might be still working
    if Harvestor.is_working():
        return {
            "status": "running",
            "speed": Harvestor._instance.queue.get_speed(),
            "progress": f"{round(Harvestor._instance.queue.get_progress())}%",
            "progressStyle": f"width: {round(Harvestor._instance.queue.get_progress())}%;",
            "workers": len(Harvestor._instance.workers),
            "totalSize": Harvestor._instance.queue.total_size,
            "copiedSize": Harvestor._instance.queue.copied_size,
            "filesLeft": Harvestor._instance.queue.unfinished_tasks
        }
    else:
       return {
            "status": "stopped"
       }


@app.post("/api/do-harvest")
def do_harvest():
    data = request.get_json()

    # Access JSON parameters (example)
    torrent_id = data.get('torrent_id')
    harvest_kind = data.get('harvest_kind')

    torrent = Torrent.get(Torrent.id == torrent_id)
    if torrent is None:
        return {
            "status": "error",
            "message": "Torrent not found"
        }, 404

    bt_client = current_app.mrf_ctx.bt_client
    if not bt_client:
        return {"status": "error", "message": "BT client not configured"}, 503

    # get path with hash
    torrent_props = bt_client.get_torrent_info(torrent.info_hash)
    content_path = torrent_props["content_path"]

    # stop
    bt_client.pause(torrent.info_hash)

    # start copying
    harvestor_config = current_app.mrf_ctx.harvestor_config
    content_kinds = harvestor_config.get("kinds")
    content_target_dir = next(item["target"] for item in content_kinds if item["name"] == harvest_kind)

    # TODO: check if the target dir exists
    Harvestor.harvest(content_path, content_target_dir, torrent_id)

    return {
        "status": "ok"
    }

@app.post("/api/stop-harvestor")
def stop_harvestor():
    Harvestor.stop()
    return {
        "status": "ok"
    }

@app.post("/api/torrent/<id>/fold")
def set_fold(id):
    torrent = Torrent.get_by_id(id)
    if torrent is None:
        return 404, {
            "status": "error",
            "message": "Torrent not found"
        }
    torrent.is_folded = True
    torrent.save()
    return {
        "status": "ok"
    }

# @app.post("/api/torrent/<id>/unfold")
# def set_unfold(id):
#     torrent = Torrent.get_by_id(id)
#     if torrent is None:
#         return 404, {
#             "status": "error",
#             "message": "Torrent not found"
#         }
#     torrent.is_folded = False
#     torrent.save()
#     return 200, {
#         "status": "ok"
#     }

@app.post("/api/torrent/autoFold")
def auto_fold():
    all_unfolded_torrents = Torrent.select().where(Torrent.is_folded == False)
    folded = 0
    for torrent in all_unfolded_torrents:
        if re.match(r"[A-Za-z]{3,5}-\d{3,4}", torrent.name) is not None or \
           re.match(r"FC2-", torrent.name):
            torrent.is_folded = True
            folded += 1
            torrent.save()

    return {
        folded: folded,
        "status": "ok"
    }

@app.post("/api/torrent/unfoldAll")
def unfold_all():
    Torrent.update(is_folded=False).execute();
    return {
        "status": "ok"
    }

def start_web_ui(host="0.0.0.0", port=5090, mrf_ctx=None):
    logger.info(f'WebUI is listening on {host}:{port}')

    with app.app_context():
        current_app.mrf_ctx = mrf_ctx

    app.run(host, port)

# def shutdown_web_ui():
#     func = request.environ.get('werkzeug.server.shutdown')
#     if func is None:
#         raise RuntimeError('Not running with the Werkzeug Server')
#     func()



