from fastapi import FastAPI, Request, Form
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from starlette.middleware.sessions import SessionMiddleware
from datetime import date
import sqlite3
import bcrypt
import uuid

app = FastAPI()
app.add_middleware(SessionMiddleware, secret_key="pizza-secret-key")
app.mount("/static", StaticFiles(directory="static"), name="static")


def get_db():
    conn = sqlite3.connect("pizza.db")
    conn.row_factory = sqlite3.Row
    return conn


def init_db():
    conn = get_db()
    conn.execute("""
        CREATE TABLE IF NOT EXISTS customers (
            id    INTEGER PRIMARY KEY AUTOINCREMENT,
            name  TEXT NOT NULL,
            phone TEXT NOT NULL
        )
    """)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS orders (
            id          INTEGER PRIMARY KEY AUTOINCREMENT,
            customer_id INTEGER NOT NULL,
            order_date  TEXT NOT NULL,
            total       REAL NOT NULL
        )
    """)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS order_details (
            id       INTEGER PRIMARY KEY AUTOINCREMENT,
            order_id INTEGER NOT NULL,
            pizza    TEXT NOT NULL,
            quantity INTEGER NOT NULL,
            price    REAL NOT NULL
        )
    """)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS users (
            id       INTEGER PRIMARY KEY AUTOINCREMENT,
            username TEXT NOT NULL UNIQUE,
            password TEXT NOT NULL,
            role     TEXT NOT NULL
        )
    """)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS login_attempts (
            id           INTEGER PRIMARY KEY AUTOINCREMENT,
            username     TEXT NOT NULL,
            success      INTEGER NOT NULL,
            attempt_date TEXT NOT NULL
        )
    """)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS reset_tokens (
            id       INTEGER PRIMARY KEY AUTOINCREMENT,
            username TEXT NOT NULL,
            token    TEXT NOT NULL UNIQUE,
            used     INTEGER NOT NULL DEFAULT 0
        )
    """)
    conn.commit()
    conn.close()


init_db()


def render(filename):
    with open(f"templates/{filename}", encoding="utf-8") as f:
        return f.read()


@app.get("/", response_class=HTMLResponse)
def index(request: Request):
    name  = request.cookies.get("customer_name", "")
    phone = request.cookies.get("customer_phone", "")
    html  = render("index.html")
    html  = html.replace("{{name}}", name).replace("{{phone}}", phone)
    return html


@app.get("/place-order", response_class=HTMLResponse)
def place_order(request: Request, name: str, phone: str, pepperoni: int = 0, cheese: int = 0, sausage: int = 0):
    conn = get_db()
    row = conn.execute("SELECT id FROM customers WHERE phone = ?", (phone,)).fetchone()
    if row:
        customer_id = row["id"]
    else:
        cur = conn.execute("INSERT INTO customers (name, phone) VALUES (?, ?)", (name, phone))
        customer_id = cur.lastrowid

    items = [
        ("Pepperoni", pepperoni, 12.99),
        ("Cheese",    cheese,    10.99),
        ("Sausage",   sausage,   12.49),
    ]
    total = sum(qty * price for _, qty, price in items if qty > 0)
    cur = conn.execute("INSERT INTO orders (customer_id, order_date, total) VALUES (?, ?, ?)", (customer_id, str(date.today()), total))
    order_id = cur.lastrowid
    for pizza, qty, price in items:
        if qty > 0:
            conn.execute("INSERT INTO order_details (order_id, pizza, quantity, price) VALUES (?, ?, ?, ?)", (order_id, pizza, qty, price))
    conn.commit()
    conn.close()

    response = HTMLResponse(f"<p>Order #{order_id} placed!</p><a href='/'>Go back</a>")
    response.set_cookie("customer_name",  name,  max_age=30*24*60*60)
    response.set_cookie("customer_phone", phone, max_age=30*24*60*60)
    return response


@app.get("/my-orders", response_class=HTMLResponse)
def my_orders(phone: str):
    conn = get_db()
    customer = conn.execute("SELECT * FROM customers WHERE phone = ?", (phone,)).fetchone()
    if not customer:
        return "<p>No orders found.</p><a href='/'>Go back</a>"
    orders = conn.execute("SELECT * FROM orders WHERE customer_id = ?", (customer["id"],)).fetchall()
    html = f"<h2>Orders for {customer['name']}</h2>"
    for o in orders:
        details = conn.execute("SELECT * FROM order_details WHERE order_id = ?", (o["id"],)).fetchall()
        html += f"<h3>Order #{o['id']} - {o['order_date']} - Total: ${o['total']:.2f}</h3><ul>"
        for d in details:
            html += f"<li>{d['pizza']} x{d['quantity']} @ ${d['price']:.2f}</li>"
        html += "</ul>"
    html += "<a href='/'>Go back</a>"
    conn.close()
    return html


@app.get("/register", response_class=HTMLResponse)
def register_page():
    return render("register.html")


@app.post("/register", response_class=HTMLResponse)
def register(username: str = Form(...), password: str = Form(...), role: str = Form(...)):
    conn = get_db()
    existing = conn.execute("SELECT id FROM users WHERE username = ?", (username,)).fetchone()
    if existing:
        conn.close()
        return "<p>Username already taken.</p><a href='/register'>Try again</a>"
    hashed = bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt())
    conn.execute("INSERT INTO users (username, password, role) VALUES (?, ?, ?)", (username, hashed.decode("utf-8"), role))
    conn.commit()
    conn.close()
    return "<p>Account created!</p><a href='/login'>Login</a>"


@app.get("/login", response_class=HTMLResponse)
def login_page():
    return render("login.html")


@app.post("/login")
def login(request: Request, username: str = Form(...), password: str = Form(...)):
    conn = get_db()
    user = conn.execute("SELECT * FROM users WHERE username = ?", (username,)).fetchone()
    success = 0
    if user and bcrypt.checkpw(password.encode("utf-8"), user["password"].encode("utf-8")):
        request.session["username"] = username
        request.session["role"]     = user["role"]
        success = 1
    conn.execute("INSERT INTO login_attempts (username, success, attempt_date) VALUES (?, ?, ?)", (username, success, str(date.today())))
    conn.commit()
    conn.close()
    if success:
        if user["role"] == "manager":
            return RedirectResponse("/manager", status_code=302)
        else:
            return RedirectResponse("/employee", status_code=302)
    return HTMLResponse("<p>Invalid username or password.</p><a href='/login'>Try again</a>")


@app.get("/logout")
def logout(request: Request):
    request.session.clear()
    return RedirectResponse("/", status_code=302)


@app.get("/forgot-password", response_class=HTMLResponse)
def forgot_password_page():
    return render("forgot_password.html")


@app.post("/forgot-password", response_class=HTMLResponse)
def forgot_password(username: str = Form(...)):
    conn = get_db()
    user = conn.execute("SELECT * FROM users WHERE username = ?", (username,)).fetchone()
    if not user:
        conn.close()
        return "<p>No account found with that username.</p><a href='/forgot-password'>Try again</a>"
    token = str(uuid.uuid4())
    conn.execute("INSERT INTO reset_tokens (username, token) VALUES (?, ?)", (username, token))
    conn.commit()
    conn.close()
    print(f"\nPASSWORD RESET LINK: http://127.0.0.1:8000/reset-password?token={token}\n")
    return "<p>Reset link generated. Check the terminal for the link.</p><a href='/login'>Back to login</a>"


@app.get("/reset-password", response_class=HTMLResponse)
def reset_password_page(token: str):
    conn = get_db()
    row = conn.execute("SELECT * FROM reset_tokens WHERE token = ? AND used = 0", (token,)).fetchone()
    conn.close()
    if not row:
        return "<p>This link is invalid or already used.</p><a href='/login'>Back to login</a>"
    html = render("reset_password.html")
    html = html.replace("{{token}}", token)
    return html


@app.post("/reset-password", response_class=HTMLResponse)
def reset_password(token: str = Form(...), new_password: str = Form(...)):
    conn = get_db()
    row = conn.execute("SELECT * FROM reset_tokens WHERE token = ? AND used = 0", (token,)).fetchone()
    if not row:
        conn.close()
        return "<p>This link is invalid or already used.</p><a href='/login'>Back to login</a>"
    hashed = bcrypt.hashpw(new_password.encode("utf-8"), bcrypt.gensalt())
    conn.execute("UPDATE users SET password = ? WHERE username = ?", (hashed.decode("utf-8"), row["username"]))
    conn.execute("UPDATE reset_tokens SET used = 1 WHERE token = ?", (token,))
    conn.commit()
    conn.close()
    return "<p>Password updated!</p><a href='/login'>Login</a>"


@app.get("/employee", response_class=HTMLResponse)
def employee(request: Request):
    if request.session.get("role") not in ("employee", "manager"):
        return RedirectResponse("/login", status_code=302)
    conn = get_db()
    orders = conn.execute("""
        SELECT o.id, o.order_date, o.total, c.name, c.phone
        FROM orders o
        JOIN customers c ON o.customer_id = c.id
    """).fetchall()
    conn.close()
    html = f"<h2>Employee View - Logged in as: {request.session.get('username')}</h2>"
    html += "<a href='/logout'>Logout</a><br><br>"
    if not orders:
        return html + "<p>No orders yet.</p>"
    for o in orders:
        conn = get_db()
        details = conn.execute("SELECT * FROM order_details WHERE order_id = ?", (o["id"],)).fetchall()
        conn.close()
        html += f"<h3>Order #{o['id']} - {o['name']} ({o['phone']}) - {o['order_date']} - Total: ${o['total']:.2f}</h3><ul>"
        for d in details:
            html += f"<li>{d['pizza']} x{d['quantity']} @ ${d['price']:.2f}</li>"
        html += "</ul>"
    return html


@app.get("/manager", response_class=HTMLResponse)
def manager(request: Request):
    if request.session.get("role") != "manager":
        return RedirectResponse("/login", status_code=302)
    conn = get_db()
    orders = conn.execute("""
        SELECT o.id, o.order_date, o.total, c.name, c.phone
        FROM orders o
        JOIN customers c ON o.customer_id = c.id
    """).fetchall()
    attempts = conn.execute("SELECT * FROM login_attempts ORDER BY id DESC").fetchall()
    conn.close()
    html = f"<h2>Manager View - Logged in as: {request.session.get('username')}</h2>"
    html += "<a href='/logout'>Logout</a><br><br>"
    html += "<h3>All Orders</h3>"
    for o in orders:
        conn = get_db()
        details = conn.execute("SELECT * FROM order_details WHERE order_id = ?", (o["id"],)).fetchall()
        conn.close()
        html += f"<h3>Order #{o['id']} - {o['name']} ({o['phone']}) - {o['order_date']} - Total: ${o['total']:.2f}</h3><ul>"
        for d in details:
            html += f"<li>{d['pizza']} x{d['quantity']} @ ${d['price']:.2f}</li>"
        html += "</ul>"
    html += "<h3>Login Attempts Log</h3><ul>"
    for a in attempts:
        status = "Success" if a["success"] else "Failed"
        html += f"<li>{a['attempt_date']} - {a['username']} - {status}</li>"
    html += "</ul>"
    return html