import sqlite3
from flask import Blueprint, request, session, redirect, render_template
from lxml import etree as ET

from app.db import get_db
from app.auth import login_required
from app.icon import fetch_icon

bp = Blueprint("main", __name__)

@bp.route("/")
@login_required
def index():
    db = get_db()
    user = db.execute("SELECT * FROM users WHERE id = ?", (session["user_id"],)).fetchone()
    return render_template("index.html", user=user)

@bp.route("/register", methods=["GET", "POST"])
def register():
    if request.method == "POST":
        username = request.form["username"]
        password = request.form["password"]

        if len(username) < 8:
            return render_template("register.html", error="Username must be at least 8 characters")
        if not any(c.islower() for c in password):
            return render_template("register.html", error="Password must contain a lowercase letter")
        if not any(c.isupper() for c in password):
            return render_template("register.html", error="Password must contain an uppercase letter")
        if not any(c in "!@#$%^&*()_+-=[]{}|;:',.<>?/`~" for c in password):
            return render_template("register.html", error="Password must contain a special character")

        db = get_db()
        try:
            db.execute("INSERT INTO users (username, password) VALUES (?, ?)", (username, password))
            db.commit()
            return redirect("/login")
        except sqlite3.IntegrityError:
            return render_template("register.html", error="Username already exists")
    return render_template("register.html")

@bp.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        username = request.form["username"]
        password = request.form["password"]
        db = get_db()
        user = db.execute("SELECT * FROM users WHERE username = ? AND password = ?", (username, password)).fetchone()
        if user:
            session["user_id"] = user["id"]
            return redirect("/")
        return render_template("login.html", error="Invalid credentials")
    return render_template("login.html")

@bp.route("/logout")
def logout():
    session.clear()
    return redirect("/login")

@bp.route("/settings", methods=["GET", "POST"])
@login_required
def settings():
    db = get_db()
    user = db.execute("SELECT * FROM users WHERE id = ?", (session["user_id"],)).fetchone()

    if request.method == "POST":
        xml_data = request.form["settings"]

        try:
            root = ET.fromstring(xml_data.encode())
        except ET.XMLSyntaxError:
            return render_template("settings.html", user=user, error="Invalid XML")

        if root.tag != "settings":
            return render_template("settings.html", user=user, error="Root element must be <settings>")

        child_tags = [elem.tag for elem in root]
        if "icon_url" not in child_tags:
            return render_template("settings.html", user=user, error="Missing <icon_url>")
        if "method" not in child_tags:
            return render_template("settings.html", user=user, error="Missing <method>")

        for elem in list(root):
            if elem.tag == "icon_url" and (not elem.text or not elem.text.startswith("https://")):
                return render_template("settings.html", user=user, error="Icon URL must start with https://")

            if elem.tag == "method" and elem.text not in ("GET", "POST"):
                return render_template("settings.html", user=user, error="Method must be GET or POST")

            if elem.tag not in ("icon_url", "method", "body"):
                root.remove(elem)

        clean = ET.tostring(root, encoding="unicode")
        db.execute("UPDATE users SET settings = ? WHERE id = ?", (clean, session["user_id"]))
        db.commit()
        return redirect("/settings")

    return render_template("settings.html", user=user)

@bp.route("/icon")
@login_required
def icon():
    db = get_db()
    user = db.execute("SELECT * FROM users WHERE id = ?", (session["user_id"],)).fetchone()

    try:
        data, content_type = fetch_icon(user["settings"])
    except Exception as e:
        return "Failed to fetch icon", 502

    if data is None:
        return "No icon URL", 400

    return data, 200, {"Content-Type": content_type}
