import logging

from flask import Blueprint, current_app, flash, redirect, render_template, request, url_for

from app.auth import ensure_fresh_token, get_active_account, login_required
from app.models import ScheduledPost
from app.services.errors import ServiceError, ValidationError
from app.services.posts import publish_now, validate_post_fields
from app.services.scheduled import create_scheduled_post, delete_scheduled_post, reschedule_post, retry_post
from app.tiktok_api import TikTokAPIError, list_videos

post_bp = Blueprint("post", __name__)
log = logging.getLogger(__name__)


@post_bp.route("/posts")
@login_required
def posts():
    account = get_active_account()
    cursor = request.args.get("cursor", "0")
    try:
        cursor = int(cursor)
    except (TypeError, ValueError):
        cursor = 0
    data = {"videos": [], "cursor": 0, "has_more": False}
    try:
        token = ensure_fresh_token(account)
        data = list_videos(token, max_count=20, cursor=cursor)
    except (TikTokAPIError, ServiceError) as e:
        flash(e.message, "warning")
    return render_template("posts.html", account=account, videos=data["videos"],
                           cursor=data["cursor"], has_more=data["has_more"])


@post_bp.route("/posts/new", methods=["GET", "POST"])
@login_required
def new_post():
    account = get_active_account()
    if request.method == "POST":
        data = request.form.to_dict()
        data["video_file"] = request.files.get("video_file")
        try:
            if request.form.get("scheduled_at"):
                post = create_scheduled_post(
                    account, data, current_app.config["MEDIA_FOLDER"],
                    upload_max_bytes=current_app.config["MAX_CONTENT_LENGTH"],
                )
                flash(f"Scheduled for {post.scheduled_at.strftime('%Y-%m-%d %H:%M UTC')}.", "success")
                return redirect(url_for("post.scheduled_posts"))
            token = ensure_fresh_token(account)
            fields = validate_post_fields(data, account.scopes)
            result = publish_now(token, fields, current_app.config["UPLOAD_FOLDER"])
            if result["publish_status"] == "FAILED":
                flash("TikTok rejected the video while processing it.", "error")
            elif fields["mode"] == "draft":
                flash("Draft sent to TikTok. Open the TikTok app and tap the inbox notification to finish and post it.", "success")
            else:
                flash(f"Post sent to TikTok (status: {result['publish_status']}). It may take a few minutes to appear on the profile.", "success")
            return redirect(url_for("post.posts"))
        except ValidationError as e:
            flash(e.message, "error")
        except (TikTokAPIError, ServiceError) as e:
            flash(e.message, "error")
        except Exception:
            log.error("posts.new failed", exc_info=True)
            flash("Could not publish the video. Try again.", "error")
    return render_template("post_new.html", account=account)


@post_bp.route("/posts/scheduled")
@login_required
def scheduled_posts():
    account = get_active_account()
    posts = ScheduledPost.query.filter_by(account_id=account.id).order_by(ScheduledPost.scheduled_at).all()
    return render_template("scheduled_posts.html", account=account, posts=posts)


@post_bp.route("/scheduled/<int:post_id>/reschedule", methods=["POST"])
@login_required
def reschedule(post_id):
    account = get_active_account()
    post = ScheduledPost.query.get_or_404(post_id)
    if post.account_id != account.id:
        flash("That scheduled post belongs to another account.", "error")
        return redirect(url_for("post.scheduled_posts"))
    try:
        reschedule_post(post, request.form.get("scheduled_at"))
        flash("Scheduled time updated.", "success")
    except ValidationError as e:
        flash(e.message, "error")
    except Exception:
        log.error("scheduled.reschedule failed", exc_info=True)
        flash("Could not reschedule the post.", "error")
    return redirect(url_for("post.scheduled_posts"))


@post_bp.route("/scheduled/<int:post_id>/delete", methods=["POST"])
@login_required
def delete_scheduled(post_id):
    account = get_active_account()
    post = ScheduledPost.query.get_or_404(post_id)
    if post.account_id != account.id:
        flash("That scheduled post belongs to another account.", "error")
        return redirect(url_for("post.scheduled_posts"))
    try:
        delete_scheduled_post(post)
        flash("Scheduled post deleted.", "success")
    except Exception:
        log.error("scheduled.delete failed", exc_info=True)
        flash("Could not delete the scheduled post.", "error")
    return redirect(url_for("post.scheduled_posts"))


@post_bp.route("/scheduled/<int:post_id>/retry", methods=["POST"])
@login_required
def retry_scheduled(post_id):
    account = get_active_account()
    post = ScheduledPost.query.get_or_404(post_id)
    if post.account_id != account.id:
        flash("That scheduled post belongs to another account.", "error")
        return redirect(url_for("post.scheduled_posts"))
    if post.status != ScheduledPost.STATUS_FAILED:
        flash("Only failed posts can be retried.", "error")
        return redirect(url_for("post.scheduled_posts"))
    retry_post(post)
    flash("Post queued again; the scheduler picks it up on the next tick.", "success")
    return redirect(url_for("post.scheduled_posts"))
