import os
import hashlib
from datetime import datetime
from flask import Flask, render_template, request, redirect, url_for, flash, jsonify, send_from_directory
from flask_sqlalchemy import SQLAlchemy
from flask_login import (
    LoginManager, UserMixin, login_user, logout_user,
    current_user, login_required
)
from reportlab.pdfgen import canvas

app = Flask(__name__)
app.secret_key = "super-secret"

# Database config (MariaDB)
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://flyhighmediaco_webdesignsignoff:K5nWngiHWKU4@localhost/flyhighmediaco_webdesignsignoff"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)

# --------------------
# Flask-Login setup
# --------------------
login_manager = LoginManager(app)
login_manager.login_view = "login"

# --------------------
# Database models
# --------------------
class User(db.Model, UserMixin):  # Inherit UserMixin for Flask-Login
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password = db.Column(db.String(200), nullable=False)  # stored MD5 ideally

    def check_password(self, raw_password):
        hashed = hashlib.md5(raw_password.encode()).hexdigest()
        return self.password == hashed


class Project(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    client_name = db.Column(db.String(100), nullable=False)
    feedback = db.Column(db.Text)
    signed_off = db.Column(db.Boolean, default=False)
    signed_off_by = db.Column(db.String(100))
    signed_off_at = db.Column(db.DateTime)
    logo_url = db.Column(db.String(255))
    primary_color = db.Column(db.String(20))
    images = db.relationship("ProjectImage", backref="project", cascade="all, delete-orphan")


class ProjectImage(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    filename = db.Column(db.String(200), nullable=False)
    version = db.Column(db.Integer, default=1)
    project_id = db.Column(db.Integer, db.ForeignKey("project.id"))
    annotations = db.relationship("Annotation", backref="image", cascade="all, delete-orphan")


class Annotation(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    project_image_id = db.Column(db.Integer, db.ForeignKey("project_image.id"))
    x = db.Column(db.Float, nullable=False)
    y = db.Column(db.Float, nullable=False)
    comment = db.Column(db.Text, nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

# --------------------
# Flask-Login loader
# --------------------
@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

# --------------------
# Routes
# --------------------
@app.route("/")
def index():
    if not current_user.is_authenticated:
        return redirect(url_for("login"))
    return redirect(url_for("dashboard"))


@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        username = request.form["username"]
        password = request.form["password"]
        user = User.query.filter_by(username=username).first()
        if user and user.check_password(password):
            login_user(user)
            flash("Welcome back!", "success")
            return redirect(url_for("dashboard"))
        else:
            flash("Invalid username or password", "danger")
            return redirect(url_for("login"))
    return render_template("login.html")


@app.route("/logout")
@login_required
def logout():
    logout_user()
    flash("Logged out successfully", "info")
    return redirect(url_for("login"))


@app.route("/dashboard")
@login_required
def dashboard():
    projects = Project.query.all()
    return render_template("dashboard.html", projects=projects)


@app.route("/project/new", methods=["GET", "POST"])
@login_required
def new_project():
    if request.method == "POST":
        name = request.form["client_name"]
        logo = request.form.get("logo_url") or None
        color = request.form.get("primary_color") or "#0d6efd"
        p = Project(client_name=name, logo_url=logo, primary_color=color)
        db.session.add(p)
        db.session.commit()
        return redirect(url_for("project_view", project_id=p.id))
    return render_template("new_project.html")


@app.route("/project/<int:project_id>")
@login_required
def project_view(project_id):
    project = Project.query.get_or_404(project_id)
    return render_template("project.html", project=project)


@app.route("/project/<int:project_id>/upload", methods=["POST"])
@login_required
def upload_image(project_id):
    project = Project.query.get_or_404(project_id)
    file = request.files["file"]
    if file:
        filename = file.filename
        upload_path = os.path.join("uploads", filename)
        file.save(upload_path)
        img = ProjectImage(filename=filename, project_id=project.id, version=len(project.images) + 1)
        db.session.add(img)
        db.session.commit()
    return redirect(url_for("project_view", project_id=project.id))


@app.route("/uploads/<path:filename>")
def uploaded_file(filename):
    return send_from_directory("uploads", filename)


@app.route("/project/<int:project_id>/client", methods=["GET", "POST"])
def client_view(project_id):
    project = Project.query.get_or_404(project_id)
    locked = project.signed_off
    if request.method == "POST":
        if "feedback" in request.form:
            project.feedback = request.form["feedback"]
            db.session.commit()
        if "signoff" in request.form:
            project.signed_off = True
            project.signed_off_by = request.form["signer_name"]
            project.signed_off_at = datetime.utcnow()
            db.session.commit()
        return redirect(url_for("client_view", project_id=project.id))
    return render_template("client_view.html", project=project, locked=locked)


@app.route("/image/<int:image_id>/annotate", methods=["POST"])
def save_annotation(image_id):
    img = ProjectImage.query.get_or_404(image_id)
    data = request.get_json()
    ann = Annotation(
        project_image_id=img.id,
        x=data["x"],
        y=data["y"],
        comment=data["comment"]
    )
    db.session.add(ann)
    db.session.commit()
    return jsonify({"status": "ok", "id": ann.id, "x": ann.x, "y": ann.y, "comment": ann.comment})


@app.route("/annotation/<int:ann_id>/delete", methods=["DELETE"])
def delete_annotation(ann_id):
    ann = Annotation.query.get_or_404(ann_id)
    db.session.delete(ann)
    db.session.commit()
    return jsonify({"status": "ok"})


@app.route("/project/<int:project_id>/export")
@login_required
def export_pdf(project_id):
    project = Project.query.get_or_404(project_id)
    filename = f"project_{project_id}_annotations.pdf"
    filepath = os.path.join("uploads", filename)
    c = canvas.Canvas(filepath)
    c.setFont("Helvetica", 14)
    c.drawString(100, 800, f"Project: {project.client_name}")
    y = 760
    for img in project.images:
        c.setFont("Helvetica-Bold", 12)
        c.drawString(100, y, f"Image: {img.filename} (v{img.version})")
        y -= 20
        for ann in img.annotations:
            c.setFont("Helvetica", 10)
            c.drawString(120, y, f"- {ann.comment} at ({ann.x:.2f}%, {ann.y:.2f}%)")
            y -= 15
    c.save()
    return send_from_directory("uploads", filename, as_attachment=True)


@app.route("/project/<int:project_id>/delete", methods=["POST"])
@login_required
def delete_project(project_id):
    project = Project.query.get_or_404(project_id)
    db.session.delete(project)
    db.session.commit()
    return redirect(url_for("dashboard"))

# --------------------
# Run
# --------------------
if __name__ == "__main__":
    with app.app_context():
        db.create_all()
    app.run(debug=True)
