"""واجهة الـ REST التي يستخدمها تطبيق الجوال (كل المسارات تحت /api)."""
import pymysql
from flask import Blueprint, g, jsonify, request
from werkzeug.security import check_password_hash, generate_password_hash

from auth import (OPEN_STATES, ApiError, find_user_by_identifier, login_required,
                  make_token, public_user, subscription_state)
from db import execute, query_all, query_one
from utils import generate_trainee_code, normalize_phone, normalize_username, whatsapp_url

bp = Blueprint("api", __name__)


def body() -> dict:
    d = request.get_json(silent=True)
    return d if isinstance(d, dict) else {}


def notify(user_id, title, text=None):
    execute("INSERT INTO notifications (user_id, title, body) VALUES (%s,%s,%s)",
            (user_id, title, text))


def build_profile(user):
    out = public_user(user)
    if user["role"] == "captain":
        c = query_one("SELECT * FROM captains WHERE user_id=%s", (user["id"],))
        state = subscription_state(c)
        out["subscription"] = {"state": state, "is_open": state in OPEN_STATES,
                               "paid_until": c["paid_until"]}
    elif user["role"] == "trainee":
        t = query_one("SELECT * FROM trainees WHERE user_id=%s", (user["id"],))
        out["trainee_code"] = t["trainee_code"]
        out["captain"] = None
        out["captain_locked"] = False
        if t["captain_id"]:
            cap = query_one("SELECT id, full_name, phone, avatar_path FROM users WHERE id=%s",
                            (t["captain_id"],))
            cap["whatsapp_url"] = whatsapp_url(cap["phone"])
            out["captain"] = cap
            state = subscription_state(query_one("SELECT * FROM captains WHERE user_id=%s",
                                                 (t["captain_id"],)))
            # إن كان كابتنه مقفولاً يبقى المتدرب قادراً على عرض برنامجه فقط
            out["captain_locked"] = state not in OPEN_STATES
    return out


@bp.get("/health")
def health():
    return jsonify(ok=True)


# ===================== التسجيل والدخول =====================
@bp.post("/register")
def register():
    d = body()
    role = d.get("role")
    if role not in ("captain", "trainee"):
        raise ApiError(400, "invalid_role", "نوع الحساب غير صحيح")

    full_name = (d.get("full_name") or "").strip()
    if not 2 <= len(full_name) <= 120:
        raise ApiError(400, "invalid_name", "الاسم غير صحيح")
    try:
        username = normalize_username(d.get("username"))
    except ValueError:
        raise ApiError(400, "invalid_username",
                       "اليوزر: 3-30 حرفاً إنجليزياً وأرقاماً (_ أو .) ويحتوي حرفاً واحداً على الأقل")
    try:
        phone = normalize_phone(d.get("phone"))
    except ValueError:
        raise ApiError(400, "invalid_phone", "رقم الهاتف غير صحيح")
    if not username and not phone:
        raise ApiError(400, "identifier_required", "أدخل يوزر أو رقم هاتف")
    password = d.get("password") or ""
    if len(password) < 6:
        raise ApiError(400, "weak_password", "كلمة المرور يجب ألا تقل عن 6 أحرف")

    try:
        uid = execute(
            "INSERT INTO users (role, full_name, username, phone, password_hash) VALUES (%s,%s,%s,%s,%s)",
            (role, full_name, username, phone, generate_password_hash(password)))
    except pymysql.err.IntegrityError:
        raise ApiError(409, "already_exists", "اليوزر أو رقم الهاتف مستخدم مسبقاً")

    if role == "captain":
        # يبدأ غير مفعّل ← الأدمن يفعّله بعد الدفع
        execute("INSERT INTO captains (user_id) VALUES (%s)", (uid,))
    else:
        for _ in range(10):
            try:
                execute("INSERT INTO trainees (user_id, trainee_code) VALUES (%s,%s)",
                        (uid, generate_trainee_code()))
                break
            except pymysql.err.IntegrityError:
                continue
        else:
            raise ApiError(500, "code_generation_failed", "تعذّر إنشاء كود المتدرب، حاول مرة أخرى")

    user = query_one("SELECT * FROM users WHERE id=%s", (uid,))
    return jsonify(token=make_token(user), user=build_profile(user)), 201


@bp.post("/login")
def login():
    d = body()
    user = find_user_by_identifier(d.get("identifier"))
    password = d.get("password") or ""
    # الأدمن يدخل من لوحة الويب فقط
    if (not user or user["role"] == "admin"
            or not check_password_hash(user["password_hash"], password)):
        raise ApiError(401, "bad_credentials", "بيانات الدخول غير صحيحة")
    if user["is_blocked"]:
        raise ApiError(403, "blocked", "هذا الحساب موقوف")
    return jsonify(token=make_token(user), user=build_profile(user))


@bp.get("/me")
@login_required()
def me():
    return jsonify(user=build_profile(g.user))


@bp.post("/me/password")
@login_required()
def change_password():
    d = body()
    if not check_password_hash(g.user["password_hash"], d.get("old_password") or ""):
        raise ApiError(400, "wrong_password", "كلمة المرور الحالية غير صحيحة")
    new = d.get("new_password") or ""
    if len(new) < 6:
        raise ApiError(400, "weak_password", "كلمة المرور يجب ألا تقل عن 6 أحرف")
    execute("UPDATE users SET password_hash=%s WHERE id=%s",
            (generate_password_hash(new), g.user["id"]))
    return jsonify(ok=True)


# ===================== الكابتن: ربط المتدربين =====================
@bp.get("/captain/trainees")
@login_required("captain", subscription=True)
def captain_trainees():
    rows = query_all(
        """SELECT u.id, u.full_name, u.phone, u.avatar_path, t.linked_at
           FROM trainees t JOIN users u ON u.id = t.user_id
           WHERE t.captain_id=%s ORDER BY u.full_name""", (g.user["id"],))
    for r in rows:
        r["whatsapp_url"] = whatsapp_url(r["phone"])
    return jsonify(trainees=rows)


@bp.post("/captain/link-requests")
@login_required("captain", subscription=True)
def captain_send_request():
    code = (body().get("trainee_code") or "").upper().replace("-", "").replace(" ", "")
    t = query_one(
        """SELECT t.user_id, t.captain_id, u.full_name
           FROM trainees t JOIN users u ON u.id = t.user_id
           WHERE t.trainee_code=%s AND u.is_blocked=0""", (code,))
    if not t:
        raise ApiError(404, "code_not_found", "الكود غير صحيح")
    if t["captain_id"] == g.user["id"]:
        raise ApiError(409, "already_linked", "هذا المتدرب مضاف عندك مسبقاً")
    if t["captain_id"]:
        raise ApiError(409, "linked_to_other", "هذا المتدرب مرتبط بكابتن آخر")
    if query_one("""SELECT id FROM link_requests
                    WHERE captain_id=%s AND trainee_id=%s AND status='pending'""",
                 (g.user["id"], t["user_id"])):
        raise ApiError(409, "already_pending", "أرسلت طلباً لهذا المتدرب وهو بانتظار الموافقة")

    rid = execute("INSERT INTO link_requests (captain_id, trainee_id) VALUES (%s,%s)",
                  (g.user["id"], t["user_id"]))
    notify(t["user_id"], "طلب ربط جديد",
           f"الكابتن {g.user['full_name']} يريد إضافتك إلى قائمة متدربيه")
    return jsonify(id=rid, status="pending", trainee_name=t["full_name"]), 201


@bp.get("/captain/link-requests")
@login_required("captain", subscription=True)
def captain_pending_requests():
    rows = query_all(
        """SELECT r.id, r.created_at, u.id AS trainee_id, u.full_name
           FROM link_requests r JOIN users u ON u.id = r.trainee_id
           WHERE r.captain_id=%s AND r.status='pending' ORDER BY r.created_at DESC""",
        (g.user["id"],))
    return jsonify(requests=rows)


@bp.delete("/captain/link-requests/<int:rid>")
@login_required("captain", subscription=True)
def captain_cancel_request(rid):
    r = query_one("SELECT id FROM link_requests WHERE id=%s AND captain_id=%s AND status='pending'",
                  (rid, g.user["id"]))
    if not r:
        raise ApiError(404, "not_found", "الطلب غير موجود")
    execute("UPDATE link_requests SET status='cancelled', responded_at=NOW() WHERE id=%s", (rid,))
    return jsonify(ok=True)


# ===================== المتدرب: الموافقة على الربط =====================
@bp.get("/trainee/link-requests")
@login_required("trainee")
def trainee_requests():
    rows = query_all(
        """SELECT r.id, r.created_at, u.id AS captain_id, u.full_name AS captain_name, u.avatar_path
           FROM link_requests r JOIN users u ON u.id = r.captain_id
           WHERE r.trainee_id=%s AND r.status='pending' ORDER BY r.created_at DESC""",
        (g.user["id"],))
    return jsonify(requests=rows)


@bp.post("/trainee/link-requests/<int:rid>/respond")
@login_required("trainee")
def trainee_respond(rid):
    accept = body().get("accept")
    if not isinstance(accept, bool):
        raise ApiError(400, "invalid_body", "أرسل accept بقيمة true أو false")
    r = query_one("""SELECT * FROM link_requests
                     WHERE id=%s AND trainee_id=%s AND status='pending' FOR UPDATE""",
                  (rid, g.user["id"]))
    if not r:
        raise ApiError(404, "not_found", "الطلب غير موجود أو تمت الإجابة عليه")

    if not accept:
        execute("UPDATE link_requests SET status='rejected', responded_at=NOW() WHERE id=%s", (rid,))
        return jsonify(ok=True, status="rejected")

    me_row = query_one("SELECT captain_id FROM trainees WHERE user_id=%s FOR UPDATE", (g.user["id"],))
    if me_row["captain_id"]:
        raise ApiError(409, "already_linked", "أنت مرتبط بكابتن حالياً، افصل الربط أولاً")
    execute("UPDATE trainees SET captain_id=%s, linked_at=NOW() WHERE user_id=%s",
            (r["captain_id"], g.user["id"]))
    execute("UPDATE link_requests SET status='accepted', responded_at=NOW() WHERE id=%s", (rid,))
    execute("""UPDATE link_requests SET status='cancelled', responded_at=NOW()
               WHERE trainee_id=%s AND status='pending' AND id<>%s""", (g.user["id"], rid))
    notify(r["captain_id"], "تمت الموافقة", f"{g.user['full_name']} انضم إلى قائمة متدربيك")
    return jsonify(ok=True, status="accepted")


@bp.post("/trainee/unlink")
@login_required("trainee")
def trainee_unlink():
    t = query_one("SELECT captain_id FROM trainees WHERE user_id=%s FOR UPDATE", (g.user["id"],))
    if not t["captain_id"]:
        raise ApiError(409, "not_linked", "أنت غير مرتبط بكابتن")
    execute("UPDATE trainees SET captain_id=NULL, linked_at=NULL WHERE user_id=%s", (g.user["id"],))
    notify(t["captain_id"], "إلغاء ربط", f"{g.user['full_name']} أنهى الارتباط بك")
    return jsonify(ok=True)
