import os
import logging
from datetime import timedelta

from flask import Flask, redirect, url_for, request
from flask_login import (
    LoginManager, UserMixin, login_user, login_required,
    logout_user, current_user
)
from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView

from sqlalchemy import create_engine, text
from sqlalchemy.engine import URL
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.ext.automap import automap_base
import bcrypt
import sys

# -------------------------
# App config
# -------------------------
app = Flask(__name__)
app.logger.setLevel(logging.INFO)
SECRET_KEY = os.environ.get("SECRET_KEY", "dev-secret")
app.secret_key = SECRET_KEY
app.permanent_session_lifetime = timedelta(hours=8)

# -------------------------
# DB engine (build from DB_* envs)
# -------------------------
db_url = URL.create(
    "mysql+pymysql",
    username=os.environ.get("DB_USER", ""),
    password=os.environ.get("DB_PASSWORD", ""),
    host=os.environ.get("DB_HOST", "127.0.0.1"),
    port=int(os.environ.get("DB_PORT", 3306)),
    database=os.environ.get("DB_NAME", ""),
    query={"charset": "utf8mb4"},
)
engine = create_engine(db_url, pool_pre_ping=True, pool_recycle=1800, future=True)
SessionLocal = scoped_session(sessionmaker(bind=engine, autoflush=False, autocommit=False))

# -------------------------
# Health endpoint (no DB)
# -------------------------
@app.get("/healthz")
def healthz():
    return "ok", 200

# -------------------------
# Auth (simple in-memory admin)
# -------------------------
class MemoryAdmin(UserMixin):
    def __init__(self, id_, email, role="admin"):
        self.id = id_
        self.email = email
        self.role = role

ADMIN_EMAIL = os.environ.get("ADMIN_EMAIL")
ADMIN_PASSWORD = os.environ.get("ADMIN_PASSWORD")
ADMIN_HASH = bcrypt.hashpw(ADMIN_PASSWORD.encode(), bcrypt.gensalt()) if ADMIN_PASSWORD else None
MEMORY_ADMIN = MemoryAdmin(id_=1, email=ADMIN_EMAIL) if ADMIN_EMAIL and ADMIN_PASSWORD else None

login_manager = LoginManager(app)
login_manager.login_view = "admin_login"

@login_manager.user_loader
def load_user(user_id):
    if MEMORY_ADMIN and str(user_id) == "1":
        return MEMORY_ADMIN
    return None

@app.route("/admin/login", methods=["GET", "POST"])
def admin_login():
    if request.method == "POST":
        email = (request.form.get("email") or "").strip().lower()
        pwd = request.form.get("password") or ""
        if MEMORY_ADMIN and email == MEMORY_ADMIN.email.lower() and bcrypt.checkpw(pwd.encode(), ADMIN_HASH):
            login_user(MEMORY_ADMIN)
            return redirect(url_for("admin.index"))
        return "Invalid credentials", 401
    return """<form method="post" style="max-width:320px;margin:3rem auto;font-family:sans-serif">
      <h3>Admin Login</h3>
      <label>Email<br><input name="email" type="email" required></label><br><br>
      <label>Password<br><input name="password" type="password" required></label><br><br>
      <button type="submit">Sign in</button>
    </form>"""

@app.route("/admin/logout")
@login_required
def admin_logout():
    logout_user()
    return redirect(url_for("admin_login"))

# -------------------------
# Admin views
# -------------------------
class SecuredModelView(ModelView):
    can_view_details = True
    can_export = True
    page_size = 50
    column_display_pk = True

    def is_accessible(self):
        return current_user.is_authenticated and getattr(current_user, "role", "") in {"admin", "editor"}

    def inaccessible_callback(self, name, **kwargs):
        return redirect(url_for("admin_login"))

    def get_session(self):
        return SessionLocal

class AppSettingsView(SecuredModelView):
    column_searchable_list = ["app_id"]
    column_filters = ["app_id"]

class PhaseContentView(SecuredModelView):
    column_searchable_list = ["section_label", "instruction_text", "question_text", "sound_tags", "prompt_template_name"]
    column_filters = ["app_id", "phase_number", "ai_prompt_id"]
    create_modal = True
    edit_modal = True

class PhasePromptAssignmentView(SecuredModelView):
    column_filters = ["app_id", "phase_number", "prompt_id"]
    form_columns = ["app_id", "phase_number", "prompt_id"]

class PromptTemplatesView(SecuredModelView):
    column_searchable_list = ["name", "description"]
    column_filters = ["organization_id", "created_at"]

class PromptMessagesView(SecuredModelView):
    column_searchable_list = ["role", "content"]
    column_filters = ["prompt_id", "sequence", "role"]
    form_columns = ["prompt_id", "sequence", "role", "content"]

class SessionFeedbackView(SecuredModelView):
    column_searchable_list = ["session_id", "feedbacktext", "summary", "rhythm_words"]
    column_filters = ["tenant_id", "user_id", "app_id", "phase_number"]
    form_excluded_columns = ["timestamp"]

# -------------------------
# Reflect & register BEFORE serving (Flask 3.x requirement)
# -------------------------
from sqlalchemy.ext.automap import automap_base
Base = automap_base()

try:
    with engine.connect() as c:
        c.execute(text("SELECT 1"))
    app.logger.info("DB ping OK")
    Base.prepare(autoload_with=engine)
    app.logger.info("Automapped classes: %s", list(Base.classes.keys()))
except Exception:
    app.logger.exception("Startup DB/reflection FAILED — exiting so systemd restarts us")
    sys.exit(1)

# Map classes
cls = Base.classes
AppSettings           = getattr(cls, "app_settings", None)
PhaseContent          = getattr(cls, "phase_content", None)
PhasePromptAssignment = getattr(cls, "phase_prompt_assignment", None)
PromptTemplates       = getattr(cls, "prompt_templates", None)
PromptMessages        = getattr(cls, "prompt_messages", None)
SessionFeedback       = getattr(cls, "session_feedback", None)

# Create admin and register views NOW
admin = Admin(app, name="Trauma Admin", url="/admin", template_mode="bootstrap4")
if AppSettings:
    admin.add_view(AppSettingsView(AppSettings, SessionLocal, category="Core"))
if PhaseContent:
    admin.add_view(PhaseContentView(PhaseContent, SessionLocal, category="Core"))
if PhasePromptAssignment:
    admin.add_view(PhasePromptAssignmentView(PhasePromptAssignment, SessionLocal, category="Prompts"))
if PromptTemplates:
    admin.add_view(PromptTemplatesView(PromptTemplates, SessionLocal, category="Prompts"))
if PromptMessages:
    admin.add_view(PromptMessagesView(PromptMessages, SessionLocal, category="Prompts"))
if SessionFeedback:
    admin.add_view(SessionFeedbackView(SessionFeedback, SessionLocal, category="Sessions"))

# -------------------------
# Entrypoint
# -------------------------
if __name__ == "__main__":
   # we moved to 5008 earlier
   app.run(host="127.0.0.1", port=5008, debug=False, threaded=True)
