"""Local teaching app: opaque cookie + server-side sessions. Run python app.py."""
import json
import secrets
import time
from pathlib import Path

from flask import Flask, jsonify, make_response, render_template, request
from werkzeug.security import check_password_hash, generate_password_hash

BASE = Path(__file__).resolve().parent
COOKIE = "ax_lab_session"
SESSION_TTL = 1800


def create_app():
    app = Flask(__name__, template_folder=str(BASE / "templates"))
    app.config["MAX_CONTENT_LENGTH"] = 4096
    sessions = {}
    app.extensions["lab_sessions"] = sessions
    users = {name: generate_password_hash("study1234") for name in ("mina", "joon")}
    results = json.loads((BASE / "sample-results.json").read_text(encoding="utf-8"))

    def error(message, status):
        return jsonify(error=message), status

    def current_user():
        sid = request.cookies.get(COOKIE)
        session = sessions.get(sid)
        if session and session["expires_at"] > time.time():
            return session["username"]
        if sid:
            sessions.pop(sid, None)
        return None

    @app.before_request
    def guard():
        if request.host != "127.0.0.1:5000":
            return error("127.0.0.1:5000 주소로 접속하세요.", 400)
        if request.method == "POST":
            if request.headers.get("Origin") != "http://127.0.0.1:5000":
                return error("같은 실습 화면에서 요청하세요.", 403)

    @app.after_request
    def headers(response):
        response.headers["Cache-Control"] = "no-store"
        response.headers["X-Content-Type-Options"] = "nosniff"
        response.headers["X-Frame-Options"] = "DENY"
        return response

    @app.get("/")
    def index():
        return render_template("index.html")

    @app.post("/api/login")
    def login():
        payload = request.get_json(silent=True)
        if not isinstance(payload, dict):
            return error("아이디와 비밀번호를 입력하세요.", 400)
        name, password = payload.get("username"), payload.get("password")
        if not isinstance(name, str) or not isinstance(password, str):
            return error("아이디와 비밀번호는 문자열이어야 합니다.", 400)
        if name not in users or not check_password_hash(users[name], password):
            return error("아이디 또는 비밀번호를 확인하세요.", 401)
        now = time.time()
        for key, session in list(sessions.items()):
            if session["expires_at"] <= now:
                sessions.pop(key, None)
        sessions.pop(request.cookies.get(COOKIE), None)
        sid = secrets.token_urlsafe(32)
        sessions[sid] = {"username": name, "expires_at": now + SESSION_TTL}
        response = make_response(jsonify(username=name))
        # HTTP localhost only. A deployed HTTPS service must use Secure cookies.
        response.set_cookie(COOKIE, sid, max_age=SESSION_TTL, httponly=True, samesite="Lax")
        return response

    @app.get("/api/me")
    def me():
        user = current_user()
        return jsonify(username=user) if user else error("먼저 로그인하세요.", 401)

    @app.get("/api/results")
    def list_results():
        user = current_user()
        if not user:
            return error("먼저 로그인하세요.", 401)
        return jsonify(results=[row for row in results if row["owner"] == user])

    @app.get("/api/results/<job_id>")
    def result(job_id):
        user = current_user()
        if not user:
            return error("먼저 로그인하세요.", 401)
        row = next((row for row in results if row["job_id"] == job_id), None)
        if row is None:
            return error("결과가 없습니다.", 404)
        if row["owner"] != user:
            return error("다른 사용자의 결과는 볼 수 없습니다.", 403)
        return jsonify(row)

    @app.post("/api/logout")
    def logout():
        sessions.pop(request.cookies.get(COOKIE), None)
        response = make_response(jsonify(message="로그아웃했습니다."))
        response.delete_cookie(COOKIE, httponly=True, samesite="Lax")
        return response

    return app


if __name__ == "__main__":
    create_app().run(host="127.0.0.1", port=5000, debug=False)
