"""
BG Remover Pro - AI Background Removal Tool
Improved version with Login/Register + 2026 SEO best practices
"""

import os
import uuid
import io
from datetime import datetime, timezone
from functools import wraps

from flask import (
    Flask, render_template, request, send_file, redirect,
    url_for, jsonify, flash, session, abort
)
from flask_sqlalchemy import SQLAlchemy
from flask_login import (
    LoginManager, UserMixin, login_user, logout_user,
    login_required, current_user
)
from werkzeug.security import generate_password_hash, check_password_hash
from werkzeug.utils import secure_filename
from rembg import remove
from rembg.bg import new_session
from PIL import Image

# =======================================================
# App Configuration
# =======================================================
app = Flask(__name__)
app.config.update(
    SECRET_KEY=os.environ.get("SECRET_KEY", "change-this-in-production-bg-remover-2026"),
    SQLALCHEMY_DATABASE_URI=os.environ.get(
        "DATABASE_URL", "sqlite:///" + os.path.join(os.path.abspath(os.path.dirname(__file__)), "instance", "users.db")
    ),
    SQLALCHEMY_TRACK_MODIFICATIONS=False,
    UPLOAD_FOLDER="static/images/uploads",
    RESULT_FOLDER="static/images/results",
    MAX_CONTENT_LENGTH=10 * 1024 * 1024,  # 10 MB
    ALLOWED_EXTENSIONS={"png", "jpg", "jpeg", "webp"},
    SESSION_COOKIE_HTTPONLY=True,
    SESSION_COOKIE_SAMESITE="Lax",
)

# Ensure folders exist
os.makedirs(app.config["UPLOAD_FOLDER"], exist_ok=True)
os.makedirs(app.config["RESULT_FOLDER"], exist_ok=True)
os.makedirs(os.path.join(app.root_path, "instance"), exist_ok=True)

db = SQLAlchemy(app)
login_manager = LoginManager(app)
login_manager.login_view = "login"
login_manager.login_message_category = "info"

# rembg session (u2net for better quality)
rembg_session = new_session("u2net")

# =======================================================
# Database Models
# =======================================================
class User(UserMixin, db.Model):
    __tablename__ = "users"
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False, index=True)
    email = db.Column(db.String(120), unique=True, nullable=False, index=True)
    password_hash = db.Column(db.String(256), nullable=False)
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    is_active = db.Column(db.Boolean, default=True)
    credits = db.Column(db.Integer, default=20)  # Free credits for logged-in users
    process_count = db.Column(db.Integer, default=0)

    def set_password(self, password: str) -> None:
        self.password_hash = generate_password_hash(password)

    def check_password(self, password: str) -> bool:
        return check_password_hash(self.password_hash, password)

    def __repr__(self):
        return f"<User {self.username}>"


class ProcessHistory(db.Model):
    __tablename__ = "process_history"
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True)
    original_file = db.Column(db.String(255))
    result_file = db.Column(db.String(255))
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
    ip_address = db.Column(db.String(45))


@login_manager.user_loader
def load_user(user_id):
    return db.session.get(User, int(user_id))


# =======================================================
# Helpers
# =======================================================
def allowed_file(filename: str) -> bool:
    return (
        "." in filename
        and filename.rsplit(".", 1)[1].lower() in app.config["ALLOWED_EXTENSIONS"]
    )


def get_client_ip() -> str:
    if request.headers.get("X-Forwarded-For"):
        return request.headers.get("X-Forwarded-For").split(",")[0].strip()
    return request.remote_addr or "0.0.0.0"


# =======================================================
# Auth Routes
# =======================================================
@app.route("/register", methods=["GET", "POST"])
def register():
    if current_user.is_authenticated:
        return redirect(url_for("index"))

    if request.method == "POST":
        username = (request.form.get("username") or "").strip()
        email = (request.form.get("email") or "").strip().lower()
        password = request.form.get("password") or ""
        confirm = request.form.get("confirm_password") or ""

        errors = []
        if not username or len(username) < 3:
            errors.append("Username must be at least 3 characters.")
        if not email or "@" not in email:
            errors.append("Valid email is required.")
        if len(password) < 8:
            errors.append("Password must be at least 8 characters.")
        if password != confirm:
            errors.append("Passwords do not match.")
        if User.query.filter_by(username=username).first():
            errors.append("Username already taken.")
        if User.query.filter_by(email=email).first():
            errors.append("Email already registered.")

        if errors:
            for e in errors:
                flash(e, "danger")
            return render_template("register.html")

        user = User(username=username, email=email, credits=20)
        user.set_password(password)
        db.session.add(user)
        db.session.commit()
        login_user(user)
        flash("Account created successfully! You have 20 free credits.", "success")
        return redirect(url_for("index"))

    return render_template("register.html")


@app.route("/login", methods=["GET", "POST"])
def login():
    if current_user.is_authenticated:
        return redirect(url_for("index"))

    if request.method == "POST":
        login_id = (request.form.get("login_id") or "").strip()
        password = request.form.get("password") or ""
        remember = bool(request.form.get("remember"))

        user = User.query.filter(
            (User.username == login_id) | (User.email == login_id.lower())
        ).first()

        if user and user.check_password(password) and user.is_active:
            login_user(user, remember=remember)
            next_page = request.args.get("next")
            flash(f"Welcome back, {user.username}!", "success")
            return redirect(next_page or url_for("index"))
        flash("Invalid username/email or password.", "danger")

    return render_template("login.html")


@app.route("/logout")
@login_required
def logout():
    logout_user()
    flash("You have been logged out.", "info")
    return redirect(url_for("index"))


@app.route("/dashboard")
@login_required
def dashboard():
    history = (
        ProcessHistory.query.filter_by(user_id=current_user.id)
        .order_by(ProcessHistory.created_at.desc())
        .limit(20)
        .all()
    )
    return render_template("dashboard.html", history=history)


# =======================================================
# Main App Routes
# =======================================================
@app.route("/")
def index():
    return render_template("index.html")


@app.route("/upload", methods=["POST"])
def upload_file():
    if "file" not in request.files:
        return jsonify({"error": "No file provided"}), 400

    file = request.files["file"]
    if not file or file.filename == "":
        return jsonify({"error": "No file selected"}), 400

    if not allowed_file(file.filename):
        return jsonify({"error": "Invalid file type. Use PNG, JPG, JPEG or WEBP."}), 400

    # Optional credit check for logged-in users (guests still free for demo)
    if current_user.is_authenticated and current_user.credits <= 0:
        return jsonify({"error": "No credits left. Please upgrade or wait for reset."}), 403

    try:
        upload_id = str(uuid.uuid4())
        original_filename = f"original_{upload_id}.png"
        result_filename = f"result_{upload_id}.png"

        original_path = os.path.join(app.config["UPLOAD_FOLDER"], original_filename)
        result_path = os.path.join(app.config["RESULT_FOLDER"], result_filename)

        # Save & process
        img = Image.open(file.stream).convert("RGBA")
        img.save(original_path, format="PNG")

        output = remove(img, session=rembg_session)
        output.save(result_path, format="PNG")

        # Update user stats
        if current_user.is_authenticated:
            current_user.credits = max(0, current_user.credits - 1)
            current_user.process_count += 1
            db.session.add(
                ProcessHistory(
                    user_id=current_user.id,
                    original_file=original_filename,
                    result_file=result_filename,
                    ip_address=get_client_ip(),
                )
            )
            db.session.commit()

        return jsonify(
            {
                "original": f"/static/images/uploads/{original_filename}",
                "result": f"/static/images/results/{result_filename}",
                "credits": current_user.credits if current_user.is_authenticated else None,
            }
        )
    except Exception as e:
        app.logger.exception("Upload processing failed")
        return jsonify({"error": "Processing failed. Please try another image."}), 500


@app.route("/download/<filename>")
def download_file(filename):
    # Security: only allow result_ files
    if not filename.startswith("result_") or ".." in filename or "/" in filename:
        abort(404)
    path = os.path.join(app.config["RESULT_FOLDER"], secure_filename(filename))
    if not os.path.isfile(path):
        abort(404)
    return send_file(path, as_attachment=True, download_name="bg-removed.png")


# =======================================================
# Static / Content Pages
# =======================================================
@app.route("/about")
def about():
    return render_template("about.html")


@app.route("/blog")
def blog():
    return render_template("blog.html")


@app.route("/contact")
def contact():
    return render_template("contact.html")


@app.route("/privacy-policy")
def privacy_policy():
    return render_template("privacy-policy.html")


@app.route("/terms-of-service")
def terms_of_service():
    return render_template("terms-of-service.html")


@app.route("/faqs")
def faqs():
    return render_template("faqs.html")


@app.route("/tools")
def tools():
    return render_template("tools.html")


@app.route("/api-documentation")
def api_documentation():
    return render_template("api-documentation.html")


@app.route("/help-center")
def help_center():
    return render_template("help-center.html")


# =======================================================
# SEO Routes
# =======================================================
@app.route("/sitemap.xml")
def sitemap():
    return send_file("static/sitemap.xml", mimetype="application/xml")


@app.route("/robots.txt")
def robots_txt():
    return send_file("robots.txt", mimetype="text/plain")


# =======================================================
# Error Handlers
# =======================================================
@app.errorhandler(404)
def not_found(e):
    return render_template("404.html"), 404


@app.errorhandler(500)
def server_error(e):
    return render_template("500.html"), 500


# =======================================================
# Init DB + Run
# =======================================================
with app.app_context():
    db.create_all()

application = app  # for passenger_wsgi / cPanel

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=5000)
