import uuid
import hashlib
import hmac
import json
from datetime import datetime
from threading import Thread
from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify, current_app
from flask_login import login_required, current_user
from app.extensions import db, csrf
from app.models.features import BackgroundTask, WebhookEndpoint

tasks_bp = Blueprint("tasks", __name__, url_prefix="/tasks")


def _generate_task_id():
    return f"task_{uuid.uuid4().hex[:16]}"


def run_background_task(app, task_id, func, *args, **kwargs):
    with app.app_context():
        task = BackgroundTask.query.filter_by(task_id=task_id).first()
        if not task:
            return
        try:
            task.status = "running"
            db.session.commit()
            result = func(*args, **kwargs)
            task.status = "completed"
            task.result_json = result if isinstance(result, dict) else {"result": str(result)}
            task.progress = 100
            task.completed_at = datetime.utcnow()
            db.session.commit()
            _fire_webhooks(task.user_id, "task.completed", {
                "task_id": task.task_id, "task_type": task.task_type, "result": task.result_json
            })
        except Exception as e:
            task.status = "failed"
            task.error_message = str(e)
            task.completed_at = datetime.utcnow()
            db.session.commit()
            _fire_webhooks(task.user_id, "task.failed", {
                "task_id": task.task_id, "task_type": task.task_type, "error": str(e)
            })


def enqueue_task(user_id, task_type, func, *args, **kwargs):
    task_id = _generate_task_id()
    task = BackgroundTask(user_id=user_id, task_type=task_type, task_id=task_id, status="pending")
    db.session.add(task)
    db.session.commit()
    app = current_app._get_current_object()
    thread = Thread(target=run_background_task, args=(app, task_id, func, *args), kwargs=kwargs)
    thread.daemon = True
    thread.start()
    return task_id


def _fire_webhooks(user_id, event, payload):
    endpoints = WebhookEndpoint.query.filter_by(user_id=user_id, is_active=True).all()
    for ep in endpoints:
        if ep.events and event not in ep.events:
            continue
        try:
            import urllib.request
            data = json.dumps({"event": event, "data": payload, "timestamp": datetime.utcnow().isoformat()}).encode()
            headers = {"Content-Type": "application/json"}
            if ep.secret:
                sig = hmac.new(ep.secret.encode(), data, hashlib.sha256).hexdigest()
                headers["X-Webhook-Signature"] = sig
            req = urllib.request.Request(ep.url, data=data, headers=headers, method="POST")
            urllib.request.urlopen(req, timeout=10)
        except Exception:
            pass


@tasks_bp.route("/")
@login_required
def index():
    page = request.args.get("page", 1, type=int)
    pagination = BackgroundTask.query.filter_by(user_id=current_user.id)\
        .order_by(BackgroundTask.created_at.desc()).paginate(page=page, per_page=20, error_out=False)
    return render_template("tasks/index.html", pagination=pagination)


@tasks_bp.route("/api/status/<task_id>")
@login_required
def status(task_id):
    task = BackgroundTask.query.filter_by(task_id=task_id, user_id=current_user.id).first_or_404()
    return jsonify({
        "task_id": task.task_id, "status": task.status, "progress": task.progress,
        "result": task.result_json, "error": task.error_message
    })


@tasks_bp.route("/webhooks")
@login_required
def webhooks():
    endpoints = WebhookEndpoint.query.filter_by(user_id=current_user.id).all()
    return render_template("tasks/webhooks.html", endpoints=endpoints)


@tasks_bp.route("/webhooks/add", methods=["POST"])
@login_required
def add_webhook():
    url = request.form.get("url", "").strip()
    events = request.form.getlist("events")
    if not url:
        flash("URL is required.", "error")
        return redirect(url_for("tasks.webhooks"))
    secret = uuid.uuid4().hex
    ep = WebhookEndpoint(user_id=current_user.id, url=url, events=events, secret=secret)
    db.session.add(ep)
    db.session.commit()
    flash(f"Webhook added. Secret: {secret}", "success")
    return redirect(url_for("tasks.webhooks"))


@tasks_bp.route("/webhooks/<int:wh_id>/delete", methods=["POST"])
@login_required
def delete_webhook(wh_id):
    ep = WebhookEndpoint.query.get_or_404(wh_id)
    if ep.user_id != current_user.id:
        flash("Access denied.", "error")
        return redirect(url_for("tasks.webhooks"))
    db.session.delete(ep)
    db.session.commit()
    flash("Webhook deleted.", "success")
    return redirect(url_for("tasks.webhooks"))
