from flask import Flask, render_template, request, jsonify
import cv2, os, json, numpy as np
from datetime import date
import uuid

app = Flask(__name__)

FACE_DB = "faces"
TEMP_DIR = "temp"
ATT_FILE = "attendance.json"

os.makedirs(FACE_DB, exist_ok=True)
os.makedirs(TEMP_DIR, exist_ok=True)

# Create attendance file
if not os.path.exists(ATT_FILE):
    with open(ATT_FILE, "w") as f:
        json.dump({}, f)

face_cascade = cv2.CascadeClassifier(
    cv2.data.haarcascades + "haarcascade_frontalface_default.xml"
)

recognizer = cv2.face.LBPHFaceRecognizer_create()

labels = {}
label_ids = {}
current_id = 0


# TRAIN MODEL
def train_model():
    global labels, label_ids, current_id

    labels = {}
    label_ids = {}
    current_id = 0

    faces_data = []
    ids = []

    for file in os.listdir(FACE_DB):
        path = os.path.join(FACE_DB, file)

        if path.endswith(".jpg"):
            img = cv2.imread(path, 0)
            if img is None:
                continue

            faces = face_cascade.detectMultiScale(img, 1.3, 5)

            for (x, y, w, h) in faces:
                roi = img[y:y+h, x:x+w]
                label = file.split(".")[0]

                if label not in label_ids:
                    label_ids[label] = current_id
                    labels[current_id] = label
                    current_id += 1

                ids.append(label_ids[label])
                faces_data.append(roi)

    if faces_data:
        recognizer.train(faces_data, np.array(ids))


train_model()


# ATTENDANCE
def load_att():
    try:
        with open(ATT_FILE, "r") as f:
            data = f.read().strip()
            return json.loads(data) if data else {}
    except:
        return {}


def save_att(data):
    with open(ATT_FILE, "w") as f:
        json.dump(data, f, indent=4)


# ROUTES
@app.route("/")
def index():
    return render_template("index.html")


@app.route("/register_page")
def register_page():
    return render_template("register.html")


@app.route("/punch")
def punch():
    return render_template("punch.html")


# REGISTER
@app.route("/register", methods=["POST"])
def register():

    if "image" not in request.files:
        return jsonify({"status": "ERROR", "msg": "No image"}), 400

    emp_id = request.form.get("emp_id")

    if not emp_id:
        return jsonify({"status": "ERROR", "msg": "ID required"}), 400

    filepath = os.path.join(FACE_DB, f"{emp_id}.jpg")

    if os.path.exists(filepath):
        return jsonify({"status": "EXISTS"})

    file = request.files["image"]
    file.save(filepath)

    train_model()

    return jsonify({"status": "REGISTERED"})


# VERIFY
@app.route("/verify", methods=["POST"])
def verify():

    if "image" not in request.files:
        return jsonify({"status": "ERROR"}), 400

    file = request.files["image"]

    filename = f"temp_{uuid.uuid4().hex}.jpg"
    filepath = os.path.join(TEMP_DIR, filename)
    file.save(filepath)

    today = str(date.today())
    data = load_att()

    try:
        img = cv2.imread(filepath, 0)
        faces = face_cascade.detectMultiScale(img, 1.2, 3)

        if len(faces) == 0:
            return jsonify({"status": "NO_FACE"})

        for (x, y, w, h) in faces:
            roi = img[y:y+h, x:x+w]

            id_, conf = recognizer.predict(roi)

            if conf < 70:
                emp_id = labels.get(id_)

                if today not in data:
                    data[today] = {}

                if emp_id not in data[today]:
                    data[today][emp_id] = {"status": "IN"}
                    save_att(data)
                    return jsonify({"status": "PUNCHIN", "emp_id": emp_id})

                elif data[today][emp_id]["status"] == "IN":
                    data[today][emp_id]["status"] = "OUT"
                    save_att(data)
                    return jsonify({"status": "PUNCHOUT", "emp_id": emp_id})

                else:
                    return jsonify({"status": "DONE", "emp_id": emp_id})

        return jsonify({"status": "UNKNOWN"})

    except Exception as e:
        return jsonify({"status": "ERROR", "msg": str(e)})

    finally:
        try:
            os.remove(filepath)
        except:
            pass


if __name__ == "__main__":
    app.run(host="office.gtechcrm.com", port=5005, debug=False, ssl_context='adhoc')