import asyncio
import io
import os
from datetime import datetime
from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify, send_file, current_app
from flask_login import login_required, current_user
from app.extensions import db, csrf, sanitize_html
from app.models.report import Report
from app.ai.diamond import run_diamond, call_ai, run_sync
from app.ai.report_generator import generate_report_html
from app.i18n import flash_i18n
from app.helpers.access import has_report_access, is_report_owner

study_bp = Blueprint("study", __name__, url_prefix="/study")


@study_bp.route("/new", methods=["GET", "POST"])
@login_required
def new():
    if request.method == "POST":
        if not current_user.can_create_report:
            flash_i18n("flash.report_limit", "error")
            return redirect(url_for("billing.plans"))

        project_name = request.form.get("project_name", "").strip()
        project_description = request.form.get("project_description", "").strip()
        user_note = request.form.get("user_note", "").strip()
        language = request.form.get("language", "ar")

        if not project_name or not project_description:
            flash_i18n("flash.all_fields_required", "error")
            return render_template("study/new.html")

        report = Report(
            user_id=current_user.id,
            project_name=project_name,
            project_description=project_description,
            user_note=user_note if user_note else None,
            language=language,
        )
        db.session.add(report)
        db.session.commit()

        return redirect(url_for("study.generate", report_id=report.id))

    return render_template("study/new.html")


@study_bp.route("/generate/<int:report_id>")
@login_required
def generate(report_id):
    report = Report.query.get_or_404(report_id)
    if report.user_id != current_user.id:
        return redirect(url_for("dashboard.index"))
    if report.full_report_html:
        return redirect(url_for("study.view", report_id=report.id))
    return render_template("study/loading.html", report=report)


@study_bp.route("/api/generate/<int:report_id>", methods=["POST"])
@csrf.exempt
@login_required
def api_generate(report_id):
    report = Report.query.get_or_404(report_id)
    if report.user_id != current_user.id:
        return jsonify({"error": "Unauthorized"}), 403
    if report.full_report_html:
        return jsonify({"status": "done", "redirect": url_for("study.view", report_id=report.id)})

    try:
        result = run_sync(
            run_diamond(report.project_name, report.project_description, report.language, report.user_note)
        )

        report.market_analysis = result["market_analysis"]
        report.financial_analysis = result["financial_analysis"]
        report.competitive_analysis = result["competitive_analysis"]
        report.synthesis_result = result["synthesis"]
        report.verdict = result["verdict"]
        report.report_references = result.get("references", [])
        report.full_report_html = sanitize_html(generate_report_html(result["synthesis"], report.language, report.report_references))
        db.session.commit()

        return jsonify({"status": "done", "redirect": url_for("study.view", report_id=report.id)})
    except Exception as e:
        current_app.logger.error(f"Report generation failed: {e}")
        return jsonify({"status": "error", "message": str(e)}), 500


@study_bp.route("/api/regenerate/<int:report_id>", methods=["POST"])
@csrf.exempt
@login_required
def api_regenerate(report_id):
    """Regenerate report with new user note."""
    report = Report.query.get_or_404(report_id)
    if report.user_id != current_user.id:
        return jsonify({"error": "Unauthorized"}), 403

    data = request.get_json(silent=True) or {}
    new_note = data.get("user_note", "").strip()

    # Update user note if provided
    if new_note:
        report.user_note = new_note
    # Use existing note if no new note provided
    user_note = new_note or report.user_note

    try:
        result = run_sync(
            run_diamond(report.project_name, report.project_description, report.language, user_note)
        )

        report.market_analysis = result["market_analysis"]
        report.financial_analysis = result["financial_analysis"]
        report.competitive_analysis = result["competitive_analysis"]
        report.synthesis_result = result["synthesis"]
        report.verdict = result["verdict"]
        report.report_references = result.get("references", [])
        report.full_report_html = sanitize_html(generate_report_html(result["synthesis"], report.language, report.report_references))
        db.session.commit()

        return jsonify({"status": "done", "redirect": url_for("study.view", report_id=report.id)})
    except Exception as e:
        current_app.logger.error(f"Report regeneration failed: {e}")
        return jsonify({"status": "error", "message": str(e)}), 500


@study_bp.route("/view/<int:report_id>")
@login_required
def view(report_id):
    report = Report.query.get_or_404(report_id)
    if not has_report_access(current_user, report):
        return redirect(url_for("dashboard.index"))

    # Log report view activity
    from app.models.features import AuditLog
    from flask import request as req
    log = AuditLog(
        user_id=current_user.id,
        action="viewed_report",
        resource_type="Report",
        resource_id=report.id,
        details={
            "project_name": report.project_name,
            "report_id": report.id,
            "language": report.language
        },
        ip_address=req.remote_addr,
        user_agent=req.headers.get('User-Agent', ''),
        log_type="general",
        status="success"
    )
    db.session.add(log)
    db.session.commit()

    from app.models.campaign import Campaign
    report_campaigns = Campaign.query.filter_by(
        user_id=current_user.id, report_id=report_id
    ).order_by(Campaign.created_at.desc()).all()
    owner = is_report_owner(current_user, report)
    return render_template("study/report.html", report=report, report_campaigns=report_campaigns, is_owner=owner)


@study_bp.route("/print/<int:report_id>")
@login_required
def print_view(report_id):
    import re as _re
    report = Report.query.get_or_404(report_id)
    if not has_report_access(current_user, report):
        return redirect(url_for("dashboard.index"))
    # Strip Alpine.js attributes so sections render fully expanded
    clean_html = report.full_report_html or ""
    clean_html = _re.sub(r'\s+x-data="[^"]*"', '', clean_html)
    clean_html = _re.sub(r"\s+x-data='[^']*'", '', clean_html)
    clean_html = _re.sub(r'\s+x-show="[^"]*"', '', clean_html)
    clean_html = _re.sub(r'\s+x-transition(?:\.[a-z.]+)?', '', clean_html)
    clean_html = _re.sub(r'\s+@click="[^"]*"', '', clean_html)
    clean_html = _re.sub(r'\s+:class="[^"]*"', '', clean_html)
    return render_template("study/print_report.html", report=report, clean_report_html=clean_html)


@study_bp.route("/share/<int:report_id>", methods=["POST"])
@login_required
def toggle_share(report_id):
    report = Report.query.get_or_404(report_id)
    if report.user_id != current_user.id:
        return jsonify({"error": "Unauthorized"}), 403
    if not report.share_token:
        report.generate_share_token()
    report.is_public = not report.is_public
    db.session.commit()
    share_url = url_for("study.public_view", token=report.share_token, _external=True) if report.is_public else None
    return jsonify({"is_public": report.is_public, "share_url": share_url})


@study_bp.route("/public/<token>")
def public_view(token):
    report = Report.query.filter_by(share_token=token, is_public=True).first_or_404()
    return render_template("study/report_public.html", report=report)


@study_bp.route("/compare")
@login_required
def compare():
    reports = Report.query.filter_by(user_id=current_user.id).filter(Report.synthesis_result.isnot(None)).order_by(Report.created_at.desc()).all()
    id1 = request.args.get("r1", type=int)
    id2 = request.args.get("r2", type=int)
    report1 = Report.query.get(id1) if id1 else None
    report2 = Report.query.get(id2) if id2 else None
    if report1 and report1.user_id != current_user.id:
        report1 = None
    if report2 and report2.user_id != current_user.id:
        report2 = None
    return render_template("study/compare.html", reports=reports, report1=report1, report2=report2)


@study_bp.route("/pdf/<int:report_id>")
@login_required
def export_pdf(report_id):
    report = Report.query.get_or_404(report_id)
    if report.user_id != current_user.id:
        return redirect(url_for("dashboard.index"))

    plan = current_user.active_plan
    if plan and not plan.can_export_pdf:
        flash("PDF export is available for Pro and Enterprise plans.", "error")
        return redirect(url_for("study.view", report_id=report.id))

    from xhtml2pdf import pisa
    import os

    fonts_dir = os.path.join(current_app.static_folder, "fonts")
    font_regular = os.path.join(fonts_dir, "Tajawal-Regular.ttf").replace("\\", "/")
    font_bold = os.path.join(fonts_dir, "Tajawal-Bold.ttf").replace("\\", "/")

    def link_callback(uri, rel):
        """Resolve Flask static URLs to absolute file paths for xhtml2pdf."""
        if uri.startswith("file:///"):
            return uri[8:]  # strip file:/// prefix
        if uri.startswith("/static/"):
            path = os.path.join(current_app.static_folder, uri.replace("/static/", ""))
            return path
        return uri

    html_content = render_template(
        "study/pdf_template.html", report=report,
        font_regular=font_regular, font_bold=font_bold,
    )
    pdf_buffer = io.BytesIO()
    pisa.CreatePDF(io.StringIO(html_content), dest=pdf_buffer, link_callback=link_callback)
    pdf_buffer.seek(0)

    return send_file(
        pdf_buffer, mimetype="application/pdf",
        as_attachment=True, download_name=f"feasibility-{report.project_name}.pdf",
    )


@study_bp.route("/pptx/<int:report_id>")
@login_required
def export_pptx(report_id):
    report = Report.query.get_or_404(report_id)
    if report.user_id != current_user.id:
        return redirect(url_for("dashboard.index"))
    plan = current_user.active_plan
    if plan and not plan.can_export_pdf:
        flash("Pitch Deck export is available for Pro and Enterprise plans.", "error")
        return redirect(url_for("study.view", report_id=report.id))
    if not report.synthesis_result:
        flash("Report not ready yet.", "error")
        return redirect(url_for("study.view", report_id=report.id))

    from app.ai.pitch_deck import generate_pitch_deck
    buffer = generate_pitch_deck(report.synthesis_result, report.project_name, report.language)
    return send_file(
        buffer,
        mimetype="application/vnd.openxmlformats-officedocument.presentationml.presentation",
        as_attachment=True,
        download_name=f"pitch-deck-{report.project_name}.pptx",
    )


@study_bp.route("/api/advisor/<int:report_id>", methods=["POST"])
@csrf.exempt
@login_required
def api_advisor(report_id):
    report = Report.query.get_or_404(report_id)
    if report.user_id != current_user.id:
        return jsonify({"error": "Unauthorized"}), 403

    data = request.get_json(silent=True) or {}
    message = data.get("message", "").strip()
    if not message:
        return jsonify({"error": "Message required"}), 400

    from app.ai.prompts.advisor import get_advisor_prompt

    try:
        messages = get_advisor_prompt(report.synthesis_result or {}, message, report.language)
        response = run_sync(call_ai(messages, model_type="fast"))
        return jsonify({"response": response})
    except Exception as e:
        current_app.logger.error(f"Advisor error: {e}")
        return jsonify({"error": str(e)}), 500


@study_bp.route("/api/edit/<int:report_id>", methods=["POST"])
@csrf.exempt
@login_required
def api_edit_report(report_id):
    """Edit synthesis_result values and regenerate report HTML."""
    report = Report.query.get_or_404(report_id)
    if report.user_id != current_user.id:
        return jsonify({"error": "Unauthorized"}), 403
    if not report.synthesis_result:
        return jsonify({"error": "Report not ready"}), 400

    data = request.get_json(silent=True) or {}
    action = data.get("action")  # "update_field", "add_item", "remove_item"
    path = data.get("path", [])  # JSON path like ["startup_cost_breakdown", "items"]
    value = data.get("value")
    index = data.get("index")

    synthesis = dict(report.synthesis_result)

    try:
        if action == "update_field":
            _set_nested(synthesis, path, value)
        elif action == "add_item":
            arr = _get_nested(synthesis, path)
            if isinstance(arr, list):
                arr.append(value)
            else:
                return jsonify({"error": "Target is not a list"}), 400
        elif action == "remove_item":
            arr = _get_nested(synthesis, path)
            if isinstance(arr, list) and isinstance(index, int) and 0 <= index < len(arr):
                arr.pop(index)
            else:
                return jsonify({"error": "Invalid index or target"}), 400
        else:
            return jsonify({"error": "Invalid action"}), 400

        report.synthesis_result = synthesis
        report.full_report_html = sanitize_html(generate_report_html(synthesis, report.language, report.report_references))
        db.session.commit()
        return jsonify({"status": "ok", "html": report.full_report_html})
    except Exception as e:
        current_app.logger.error(f"Edit report error: {e}")
        return jsonify({"error": str(e)}), 500


def _get_nested(obj, path):
    """Traverse a nested dict/list by path keys."""
    current = obj
    for key in path:
        if isinstance(current, dict):
            current = current.get(key)
        elif isinstance(current, list) and isinstance(key, int):
            current = current[key] if 0 <= key < len(current) else None
        else:
            return None
    return current


def _set_nested(obj, path, value):
    """Set a value in a nested dict/list by path keys."""
    current = obj
    for key in path[:-1]:
        if isinstance(current, dict):
            current = current.setdefault(key, {})
        elif isinstance(current, list) and isinstance(key, int):
            current = current[key]
    last_key = path[-1]
    if isinstance(current, dict):
        current[last_key] = value
    elif isinstance(current, list) and isinstance(last_key, int):
        current[last_key] = value


@study_bp.route("/duplicate/<int:report_id>")
@login_required
def duplicate(report_id):
    report = Report.query.get_or_404(report_id)
    if report.user_id != current_user.id:
        return redirect(url_for("dashboard.index"))
    new_report = Report(
        user_id=current_user.id,
        project_name=f"{report.project_name} (نسخة)",
        project_description=report.project_description,
        user_note=report.user_note,
        language=report.language,
    )
    db.session.add(new_report)
    db.session.commit()
    flash("تم نسخ الدراسة. يمكنك إعادة تشغيل التحليل.", "success")
    return redirect(url_for("study.new"))


@study_bp.route("/api/followup/<int:report_id>", methods=["POST"])
@csrf.exempt
@login_required
def api_followup(report_id):
    report = Report.query.get_or_404(report_id)
    if report.user_id != current_user.id:
        return jsonify({"error": "Unauthorized"}), 403
    if not report.synthesis_result:
        return jsonify({"error": "Report not ready"}), 400

    try:
        prompt = f"""Based on this feasibility study synthesis for "{report.project_name}":
{report.project_description}

Generate 5 smart follow-up questions that would help refine and improve this feasibility study.
Questions should cover: team, funding, timeline, market specifics, and operations.
Return as JSON array of strings. Language: {"Arabic" if report.language == "ar" else "English"}."""

        messages = [{"role": "system", "content": "Return only a JSON array of 5 strings."}, {"role": "user", "content": prompt}]
        response = run_sync(call_ai(messages, model_type="fast"))
        import json
        try:
            questions = json.loads(response)
        except Exception:
            questions = [q.strip().strip('"').strip("'") for q in response.strip("[]").split(",") if q.strip()]
        return jsonify({"questions": questions[:5]})
    except Exception as e:
        current_app.logger.error(f"Follow-up questions error: {e}")
        return jsonify({"questions": []})


# ══════════════════════════════════════════════════════════════
# NotebookLM Integration Routes
# ══════════════════════════════════════════════════════════════

@study_bp.route("/notebook/<int:report_id>")
@login_required
def notebook_view(report_id):
    report = Report.query.get_or_404(report_id)
    if not has_report_access(current_user, report):
        return redirect(url_for("dashboard.index"))
    if not report.synthesis_result:
        flash("يجب إنشاء التقرير أولاً.", "error")
        return redirect(url_for("study.view", report_id=report.id))

    from app.models.report import ReportNotebook, NotebookAsset
    from app.ai.notebooklm_service import ASSET_DISPLAY, check_session_valid

    nb = ReportNotebook.query.filter_by(report_id=report.id).first()
    assets = NotebookAsset.query.filter_by(report_id=report.id).order_by(NotebookAsset.asset_type, NotebookAsset.asset_index).all()

    # Auto-reset stale "generating" assets (stuck > 10 minutes)
    stale_reset = False
    for a in assets:
        if a.status == "generating" and a.created_at:
            age_minutes = (datetime.utcnow() - (a.completed_at or a.created_at)).total_seconds() / 60
            if age_minutes > 10:
                # Check if file exists despite timeout
                if a.file_path:
                    full_path = os.path.join(current_app.static_folder, a.file_path)
                    if os.path.exists(full_path):
                        # File was created - mark as ready
                        a.status = "ready"
                        a.error_message = None
                        a.completed_at = datetime.utcnow()
                        stale_reset = True
                        continue

                # No file or stale generating - mark as failed
                a.status = "failed"
                a.error_message = "انتهت مهلة الإنشاء. اضغط إعادة المحاولة."
                stale_reset = True
    if stale_reset:
        db.session.commit()

    # Group assets by type for multiple asset support
    assets_grouped = {}
    for a in assets:
        if a.asset_type not in assets_grouped:
            assets_grouped[a.asset_type] = []
        assets_grouped[a.asset_type].append(a)

    # Also maintain single asset map for backward compatibility
    assets_map = {}
    for asset_type, asset_list in assets_grouped.items():
        # Prefer ready assets with files, then ready assets, then first asset
        ready_with_files = [a for a in asset_list if a.status == "ready" and a.file_path]
        ready_assets = [a for a in asset_list if a.status == "ready"]
        if ready_with_files:
            assets_map[asset_type] = ready_with_files[0]
        elif ready_assets:
            assets_map[asset_type] = ready_assets[0]
        else:
            assets_map[asset_type] = asset_list[0]

    nlm_mode = current_app.config.get("NOTEBOOKLM_MODE", "admin_shared")
    if nlm_mode == "admin_shared":
        google_connected = check_session_valid("admin")
    elif nlm_mode == "admin_pool":
        # For admin_pool, check if there are any healthy admin accounts
        from app.ai.nlm_admin_service import get_available_admin_account
        admin_account = get_available_admin_account()
        google_connected = admin_account is not None
    else:
        google_connected = check_session_valid(current_user.id)

    return render_template(
        "study/notebook.html",
        report=report,
        notebook=nb,
        assets_map=assets_map,
        assets_grouped=assets_grouped,
        asset_display=ASSET_DISPLAY,
        google_connected=google_connected,
        nlm_mode=nlm_mode,
        notebooklm_enabled=current_app.config.get("NOTEBOOKLM_ENABLED", False),
    )


def _nlm_admin_account():
    """Get an admin NotebookLM account for creating notebooks."""
    from app.ai.nlm_admin_service import get_available_admin_account, mark_account_unhealthy

    mode = current_app.config.get("NOTEBOOKLM_MODE", "admin_shared")

    if mode == "admin_pool":
        account = get_available_admin_account()
        if account:
            return account
        else:
            current_app.logger.warning("No available admin accounts, all may be at capacity")
            return None

    return None  # Will use user's own account or single admin account


@study_bp.route("/api/notebook/create/<int:report_id>", methods=["POST"])
@csrf.exempt
@login_required
def api_notebook_create(report_id):
    """Create a NotebookLM notebook and add report data as source."""
    report = Report.query.get_or_404(report_id)
    if report.user_id != current_user.id:
        return jsonify({"error": "Unauthorized"}), 403
    if not report.synthesis_result:
        return jsonify({"error": "Report not ready"}), 400

    from app.models.report import ReportNotebook

    existing = ReportNotebook.query.filter_by(report_id=report.id).first()
    if existing:
        return jsonify({
            "status": "exists",
            "notebook_id": existing.notebook_id,
            "notebook_url": existing.notebook_url,
        })

    data = request.get_json(silent=True) or {}
    use_rag = data.get("use_rag", False)

    # If RAG mode is requested or if NotebookLM is not configured
    if use_rag or not current_app.config.get("NOTEBOOKLM_ENABLED"):
        try:
            from app.ai.rag_service import create_rag_notebook
            notebook_url = create_rag_notebook(report.id, current_user.id)

            if notebook_url:
                nb = ReportNotebook(
                    report_id=report.id,
                    notebook_id=f"rag_{report.id}",
                    source_id=None,
                    notebook_url=notebook_url,
                )
                db.session.add(nb)
                db.session.commit()

                return jsonify({
                    "status": "created",
                    "notebook_id": f"rag_{report.id}",
                    "notebook_url": notebook_url,
                    "mode": "rag",
                })
        except Exception as e:
            current_app.logger.error(f"RAG notebook create error: {e}")
            # Fall through to try NotebookLM

    # Try NotebookLM with admin pool
    admin_account = None
    try:
        from app.ai.notebooklm_service import create_notebook_for_report, run_sync
        from app.ai.nlm_admin_service import get_available_admin_account, mark_account_used, mark_account_unhealthy

        # Get available admin account
        admin_account = get_available_admin_account()

        if not admin_account:
            return jsonify({
                "error": "no_admin_accounts",
                "message": "لا توجد حسابات مسؤول NotebookLM متاحة. يرجى الاتصال بالدعم."
            }), 503

        # Create notebook with admin account
        notebook_id, source_id, notebook_url = run_sync(
            create_notebook_for_report(report, admin_account_id=admin_account.id)
        )

        nb = ReportNotebook(
            report_id=report.id,
            notebook_id=notebook_id,
            source_id=source_id,
            notebook_url=notebook_url,
            nlm_account_id=admin_account.id,
            mode="notebooklm",
        )
        db.session.add(nb)
        db.session.commit()

        # Mark account as used
        mark_account_used(admin_account.id)

        return jsonify({
            "status": "created",
            "notebook_id": notebook_id,
            "notebook_url": notebook_url,
            "mode": "notebooklm",
            "admin_account": admin_account.name,
        })

    except Exception as e:
        current_app.logger.error(f"NotebookLM create error: {e}")
        # Mark admin account as unhealthy if error occurred
        if admin_account:
            from app.ai.nlm_admin_service import mark_account_unhealthy
            mark_account_unhealthy(admin_account.id, str(e))

        # Try RAG as fallback
        try:
            from app.ai.rag_service import create_rag_notebook
            notebook_url = create_rag_notebook(report.id, current_user.id)

            if notebook_url:
                nb = ReportNotebook(
                    report_id=report.id,
                    notebook_id=f"rag_{report.id}",
                    source_id=None,
                    notebook_url=notebook_url,
                    mode="rag",
                )
                db.session.add(nb)
                db.session.commit()

                return jsonify({
                    "status": "created",
                    "notebook_id": f"rag_{report.id}",
                    "notebook_url": notebook_url,
                    "mode": "rag",
                    "fallback": True,
                })
        except Exception as rag_error:
            current_app.logger.error(f"RAG fallback error: {rag_error}")

        return jsonify({"error": str(e)}), 500


@study_bp.route("/api/notebook/generate/<int:report_id>", methods=["POST"])
@csrf.exempt
@login_required
def api_notebook_generate(report_id):
    """Generate a specific asset type in the notebook."""
    report = Report.query.get_or_404(report_id)
    if report.user_id != current_user.id:
        return jsonify({"error": "Unauthorized"}), 403

    from app.models.report import ReportNotebook, NotebookAsset
    from app.ai.notebooklm_service import ASSET_GENERATE_MAP

    nb = ReportNotebook.query.filter_by(report_id=report.id).first()
    if not nb:
        return jsonify({"error": "Notebook not created yet"}), 400

    data = request.get_json(silent=True) or {}
    asset_type = data.get("type", "").strip()

    if asset_type not in ASSET_GENERATE_MAP:
        return jsonify({"error": f"Invalid asset type: {asset_type}"}), 400

    asset = NotebookAsset.query.filter_by(
        report_id=report.id, asset_type=asset_type
    ).first()

    if asset and asset.status == "ready":
        return jsonify({"status": "ready", "asset_id": asset.id})

    if not asset:
        asset = NotebookAsset(
            report_id=report.id,
            notebook_ref_id=nb.id,
            asset_type=asset_type,
            status="generating",
        )
        db.session.add(asset)
        db.session.commit()
    else:
        asset.status = "generating"
        asset.error_message = None
        db.session.commit()

    import os
    nlm_error = None

    # --- Try NotebookLM first ---
    try:
        from app.ai.notebooklm_service import generate_asset, download_asset, run_sync as nlm_run_sync, _get_uploads_dir, ASSET_DOWNLOAD_MAP

        # Get admin account ID if notebook was created with admin account
        admin_account_id = nb.nlm_account_id if nb.nlm_account_id else None

        nlm_run_sync(generate_asset(nb.notebook_id, asset_type, report.language, admin_account_id=admin_account_id))

        uploads_dir = _get_uploads_dir(report.id)
        output_base = os.path.join(uploads_dir, asset_type)
        file_path, file_format = nlm_run_sync(
            download_asset(nb.notebook_id, asset_type, output_base, admin_account_id=admin_account_id)
        )

        rel_path = os.path.relpath(file_path, current_app.static_folder).replace("\\", "/")
        asset.status = "ready"
        asset.file_path = rel_path
        asset.file_format = file_format
        asset.completed_at = datetime.utcnow()
        db.session.commit()

        return jsonify({
            "status": "ready",
            "asset_id": asset.id,
            "file_url": f"/static/{rel_path}",
        })

    except Exception as e:
        current_app.logger.error(f"NotebookLM generate {asset_type} error: {e}")
        err_str = str(e).lower()
        if "rate limit" in err_str or "quota" in err_str:
            asset.status = "failed"
            asset.error_message = "تم تجاوز حد الاستخدام في NotebookLM. حاول مرة أخرى بعد عدة دقائق."
        else:
            asset.status = "failed"
            asset.error_message = str(e)
        db.session.commit()
        return jsonify({"error": asset.error_message, "status": "failed"}), 500


@study_bp.route("/api/notebook/reset-asset/<int:report_id>", methods=["POST"])
@csrf.exempt
@login_required
def api_notebook_reset_asset(report_id):
    """Force-reset a stuck 'generating' asset so user can retry."""
    report = Report.query.get_or_404(report_id)
    if report.user_id != current_user.id:
        return jsonify({"error": "Unauthorized"}), 403

    from app.models.report import NotebookAsset
    data = request.get_json(silent=True) or {}
    asset_type = data.get("type", "").strip()

    asset = NotebookAsset.query.filter_by(
        report_id=report.id, asset_type=asset_type
    ).first()
    if not asset:
        return jsonify({"error": "Asset not found"}), 404

    asset.status = "failed"
    asset.error_message = "تم إعادة التعيين يدوياً. اضغط إعادة المحاولة."
    db.session.commit()
    return jsonify({"status": "reset"})


@study_bp.route("/notebook/flashcards/<int:report_id>")
@login_required
def notebook_flashcards_view(report_id):
    """Interactive flashcards viewer."""
    report = Report.query.get_or_404(report_id)
    if not has_report_access(current_user, report):
        abort(403)

    from app.models.report import NotebookAsset
    import os, json

    # Support for multiple assets via index parameter
    asset_index = request.args.get('index', 1, type=int)

    asset = NotebookAsset.query.filter_by(
        report_id=report.id, asset_type="flashcards", asset_index=asset_index
    ).first()

    if not asset or asset.status != "ready" or not asset.file_path:
        flash("البطاقات التعليمية غير جاهزة بعد.", "error")
        return redirect(url_for("study.notebook_view", report_id=report.id))

    full_path = os.path.join(current_app.static_folder, asset.file_path)
    if not os.path.exists(full_path):
        flash("ملف البطاقات غير موجود.", "error")
        return redirect(url_for("study.notebook_view", report_id=report.id))

    with open(full_path, "r", encoding="utf-8") as f:
        fc_data = json.load(f)

    return render_template(
        "study/flashcards.html",
        report=report,
        flashcards_data=json.dumps(fc_data, ensure_ascii=False),
        share_asset_id=asset.id,
        asset_label=f"بطاقات تعليمية (نسخة {asset_index})",
    )


@study_bp.route("/notebook/view/<int:report_id>/<asset_type>")
@login_required
def notebook_asset_view(report_id, asset_type):
    """Unified asset viewer for audio, video, report, infographic, slide_deck."""
    report = Report.query.get_or_404(report_id)
    if not has_report_access(current_user, report):
        abort(403)

    from app.models.report import NotebookAsset
    from app.ai.notebooklm_service import ASSET_DISPLAY
    import os, json

    allowed = ("audio", "video", "report", "infographic", "slide_deck")
    if asset_type not in allowed:
        abort(404)

    # Support for multiple assets via index parameter
    asset_index = request.args.get('index', 1, type=int)

    asset = NotebookAsset.query.filter_by(
        report_id=report.id, asset_type=asset_type, asset_index=asset_index
    ).first()

    if not asset or asset.status != "ready" or not asset.file_path:
        flash("هذا المحتوى غير جاهز بعد.", "error")
        return redirect(url_for("study.notebook_view", report_id=report.id))

    full_path = os.path.join(current_app.static_folder, asset.file_path)
    if not os.path.exists(full_path):
        flash("الملف غير موجود.", "error")
        return redirect(url_for("study.notebook_view", report_id=report.id))

    file_url = f"/static/{asset.file_path}"
    asset_info = ASSET_DISPLAY.get(asset_type, {})

    extra = {}
    is_html = asset.file_format == "html" or full_path.endswith(".html")
    if is_html:
        with open(full_path, "r", encoding="utf-8") as f:
            extra["html_content"] = f.read()
    elif asset_type == "report":
        with open(full_path, "r", encoding="utf-8") as f:
            extra["report_content"] = json.dumps(f.read(), ensure_ascii=False)

    return render_template(
        "study/asset_viewer.html",
        report=report,
        asset=asset,
        asset_type=asset_type,
        asset_info=asset_info,
        file_url=file_url,
        share_asset_id=asset.id,
        asset_label=asset_info.get("label_ar", asset_type),
        is_html=is_html,
        **extra,
    )


@study_bp.route("/notebook/quiz/<int:report_id>")
@login_required
def notebook_quiz_view(report_id):
    """Interactive quiz viewer for a report's generated quiz."""
    report = Report.query.get_or_404(report_id)
    if not has_report_access(current_user, report):
        abort(403)

    from app.models.report import NotebookAsset
    import os, json

    # Support for multiple assets via index parameter
    asset_index = request.args.get('index', 1, type=int)

    asset = NotebookAsset.query.filter_by(
        report_id=report.id, asset_type="quiz", asset_index=asset_index
    ).first()

    if not asset or asset.status != "ready" or not asset.file_path:
        flash("الاختبار غير جاهز بعد.", "error")
        return redirect(url_for("study.notebook_view", report_id=report.id))

    full_path = os.path.join(current_app.static_folder, asset.file_path)
    if not os.path.exists(full_path):
        flash("ملف الاختبار غير موجود.", "error")
        return redirect(url_for("study.notebook_view", report_id=report.id))

    with open(full_path, "r", encoding="utf-8") as f:
        quiz_data = json.load(f)

    return render_template(
        "study/quiz.html",
        report=report,
        quiz_data=json.dumps(quiz_data, ensure_ascii=False),
        share_asset_id=asset.id,
        asset_label=f"اختبار (نسخة {asset_index})",
    )


@study_bp.route("/notebook/mindmap/<int:report_id>")
@login_required
def notebook_mindmap_view(report_id):
    """Interactive mind map viewer for a report's generated mind map."""
    report = Report.query.get_or_404(report_id)
    if not has_report_access(current_user, report):
        abort(403)

    from app.models.report import NotebookAsset
    import os, json

    # Support for multiple assets via index parameter
    asset_index = request.args.get('index', 1, type=int)

    asset = NotebookAsset.query.filter_by(
        report_id=report.id, asset_type="mind_map", asset_index=asset_index
    ).first()

    if not asset or asset.status != "ready" or not asset.file_path:
        flash("الخريطة الذهنية غير جاهزة بعد.", "error")
        return redirect(url_for("study.notebook_view", report_id=report.id))

    full_path = os.path.join(current_app.static_folder, asset.file_path)
    if not os.path.exists(full_path):
        flash("ملف الخريطة الذهنية غير موجود.", "error")
        return redirect(url_for("study.notebook_view", report_id=report.id))

    with open(full_path, "r", encoding="utf-8") as f:
        mindmap_data = json.load(f)

    return render_template(
        "study/mindmap.html",
        report=report,
        mindmap_data=json.dumps(mindmap_data, ensure_ascii=False),
        share_asset_id=asset.id,
        asset_label=f"خريطة ذهنية (نسخة {asset_index})",
    )


@study_bp.route("/api/notebook/status/<int:report_id>")
@login_required
def api_notebook_status(report_id):
    """Get status of all notebook assets for a report."""
    report = Report.query.get_or_404(report_id)
    if report.user_id != current_user.id:
        return jsonify({"error": "Unauthorized"}), 403

    from app.models.report import ReportNotebook, NotebookAsset

    nb = ReportNotebook.query.filter_by(report_id=report.id).first()
    assets = NotebookAsset.query.filter_by(report_id=report.id).all()

    return jsonify({
        "notebook": {
            "id": nb.notebook_id,
            "url": nb.notebook_url,
        } if nb else None,
        "assets": {
            a.asset_type: {
                "id": a.id,
                "status": a.status,
                "file_url": f"/static/{a.file_path}" if a.file_path else None,
                "format": a.file_format,
                "error": a.error_message,
            }
            for a in assets
        },
    })


@study_bp.route("/api/notebook/download/<int:asset_id>")
@login_required
def api_notebook_download(asset_id):
    """Download a generated notebook asset file."""
    from app.models.report import NotebookAsset
    import os

    asset = NotebookAsset.query.get_or_404(asset_id)
    report = Report.query.get_or_404(asset.report_id)
    if not has_report_access(current_user, report):
        return jsonify({"error": "Unauthorized"}), 403

    if asset.status != "ready" or not asset.file_path:
        return jsonify({"error": "Asset not ready"}), 400

    full_path = os.path.join(current_app.static_folder, asset.file_path)
    if not os.path.exists(full_path):
        return jsonify({"error": "File not found"}), 404

    from app.ai.notebooklm_service import ASSET_DISPLAY
    display = ASSET_DISPLAY.get(asset.asset_type, {})
    label = display.get("label_en", asset.asset_type)
    filename = f"{report.project_name}-{label}.{asset.file_format}"

    return send_file(
        full_path,
        as_attachment=True,
        download_name=filename,
    )


@study_bp.route("/api/notebook/share/<int:asset_id>", methods=["POST"])
@csrf.exempt
@login_required
def api_notebook_share(asset_id):
    """Generate a public share link for a notebook asset."""
    from app.models.report import NotebookAsset
    import secrets

    asset = NotebookAsset.query.get_or_404(asset_id)
    report = Report.query.get_or_404(asset.report_id)
    if report.user_id != current_user.id:
        return jsonify({"error": "Unauthorized"}), 403

    if asset.status != "ready":
        return jsonify({"error": "Asset not ready"}), 400

    if not asset.share_token:
        asset.share_token = secrets.token_urlsafe(32)
        db.session.commit()

    share_url = url_for("study.public_asset_view", token=asset.share_token, _external=True)
    return jsonify({"share_url": share_url, "token": asset.share_token})


@study_bp.route("/shared/<token>")
def public_asset_view(token):
    """Public view of a shared notebook asset — no login required."""
    from app.models.report import NotebookAsset
    from app.ai.notebooklm_service import ASSET_DISPLAY
    import os, json

    asset = NotebookAsset.query.filter_by(share_token=token).first_or_404()
    report = Report.query.get_or_404(asset.report_id)

    if asset.status != "ready" or not asset.file_path:
        abort(404)

    full_path = os.path.join(current_app.static_folder, asset.file_path)
    if not os.path.exists(full_path):
        abort(404)

    asset_info = ASSET_DISPLAY.get(asset.asset_type, {})
    file_url = f"/static/{asset.file_path}"
    at = asset.asset_type

    # JSON-based viewers
    if at in ("mind_map", "quiz", "flashcards"):
        with open(full_path, "r", encoding="utf-8") as f:
            json_data = json.load(f)
        data_str = json.dumps(json_data, ensure_ascii=False)
        if at == "mind_map":
            return render_template("study/mindmap.html", report=report, mindmap_data=data_str, shared=True)
        elif at == "quiz":
            return render_template("study/quiz.html", report=report, quiz_data=data_str, shared=True)
        elif at == "flashcards":
            return render_template("study/flashcards.html", report=report, flashcards_data=data_str, shared=True)

    # Report (markdown)
    extra = {}
    if at == "report":
        with open(full_path, "r", encoding="utf-8") as f:
            extra["report_content"] = json.dumps(f.read(), ensure_ascii=False)

    return render_template(
        "study/asset_viewer.html",
        report=report,
        asset=asset,
        asset_type=at,
        asset_info=asset_info,
        file_url=file_url,
        shared=True,
        **extra,
    )


@study_bp.route("/api/notebook/connect-google", methods=["POST"])
@csrf.exempt
@login_required
def api_notebook_connect_google():
    """Start Google login flow for NotebookLM via Playwright."""
    try:
        from app.ai.notebooklm_service import start_google_login_sync, get_user_storage_path

        storage_path = start_google_login_sync(current_user.id)

        current_user.google_nlm_session_path = storage_path
        current_user.google_nlm_connected_at = datetime.utcnow()
        db.session.commit()

        return jsonify({"status": "connected", "message": "تم ربط حساب Google بنجاح"})
    except Exception as e:
        current_app.logger.error(f"NotebookLM Google connect error: {e}")
        return jsonify({"error": str(e)}), 500


@study_bp.route("/api/notebook/auth-status")
@login_required
def api_notebook_auth_status():
    """Check if the current user has a valid NotebookLM session."""
    from app.ai.notebooklm_service import check_session_valid

    connected = check_session_valid(current_user.id)
    return jsonify({
        "connected": connected,
        "connected_at": current_user.google_nlm_connected_at.isoformat() if current_user.google_nlm_connected_at else None,
    })


@study_bp.route("/api/notebook/connect-with-oauth", methods=["POST"])
@csrf.exempt
@login_required
def api_notebook_connect_with_oauth():
    """
    Connect to NotebookLM using notebooklm CLI.
    This will open a browser window for the user to log in to Google.
    """
    try:
        import subprocess
        import os
        from app.ai.notebooklm_service import get_user_session_dir

        # Get user's session directory
        user_dir = get_user_session_dir(current_user.id)
        os.makedirs(user_dir, exist_ok=True)

        # Set custom NOTEBOOKLM_HOME for this user
        env = os.environ.copy()
        env["NOTEBOOKLM_HOME"] = user_dir

        # Check if DISPLAY is set, if not start Xvfb
        display = env.get("DISPLAY", ":99")
        if not os.path.exists(f"/tmp/.X11-unix/X{display.split(':')[-1]}"):
            try:
                subprocess.Popen(
                    ["Xvfb", display, "-screen", "0", "1280x720x24", "-ac"],
                    stdout=subprocess.DEVNULL,
                    stderr=subprocess.DEVNULL
                )
                import time
                time.sleep(1)
            except:
                pass

        env["DISPLAY"] = display

        # Run notebooklm login
        try:
            result = subprocess.run(
                ["notebooklm", "login"],
                env=env,
                timeout=300,
                capture_output=True,
                text=True
            )

            # Check if storage_state.json was created
            storage_path = os.path.join(user_dir, "storage_state.json")
            if os.path.exists(storage_path):
                current_user.google_nlm_session_path = storage_path
                current_user.google_nlm_connected_at = datetime.utcnow()
                db.session.commit()

                return jsonify({
                    "status": "connected",
                    "message": "تم ربط حساب Google بـ NotebookLM بنجاح"
                })
            else:
                return jsonify({
                    "error": "authentication_failed",
                    "message": "لم يتم إنشاء ملف الجلسة. يرجى المحاولة مرة أخرى."
                }), 400

        except subprocess.TimeoutExpired:
            return jsonify({
                "error": "timeout",
                "message": "انتهت مهلة المصادقة (5 دقائق). يرجى المحاولة مرة أخرى."
            }), 400

    except Exception as e:
        current_app.logger.error(f"NotebookLM connection error: {e}")
        import traceback
        current_app.logger.error(traceback.format_exc())
        return jsonify({"error": str(e), "message": "حدث خطأ أثناء ربط الحساب"}), 500


@study_bp.route("/api/notebook/disconnect", methods=["POST"])
@login_required
def api_notebook_disconnect():
    """Disconnect user's NotebookLM session."""
    try:
        import os
        from app.ai.notebooklm_service import get_user_storage_path

        storage_path = current_user.google_nlm_session_path

        # Clear database fields
        current_user.google_nlm_session_path = None
        current_user.google_nlm_connected_at = None
        db.session.commit()

        # Delete storage file if exists
        if storage_path and os.path.exists(storage_path):
            try:
                os.remove(storage_path)
            except Exception:
                pass

        return jsonify({"status": "disconnected", "message": "تم فصل ربط حساب NotebookLM"})

    except Exception as e:
        current_app.logger.error(f"NotebookLM disconnect error: {e}")
        return jsonify({"error": str(e)}), 500


@study_bp.route("/api/notebook/query/<int:report_id>", methods=["POST"])
@csrf.exempt
@login_required
def api_notebook_query(report_id):
    """Query a RAG notebook with a question."""
    try:
        from app.ai.rag_service import query_rag_notebook
        from app.models.report import ReportNotebook, Report

        report = Report.query.get_or_404(report_id)
        if report.user_id != current_user.id:
            return jsonify({"error": "Unauthorized"}), 403

        # Check if this report has a RAG notebook
        nb = ReportNotebook.query.filter_by(report_id=report.id).first()
        if not nb or not nb.notebook_id.startswith("rag_"):
            return jsonify({"error": "No RAG notebook found for this report"}), 400

        data = request.get_json(silent=True) or {}
        question = data.get("question", "").strip()

        if not question:
            return jsonify({"error": "Question is required"}), 400

        answer = query_rag_notebook(report_id, current_user.id, question)

        return jsonify({
            "status": "success",
            "answer": answer,
        })

    except Exception as e:
        current_app.logger.error(f"RAG query error: {e}")
        import traceback
        current_app.logger.error(traceback.format_exc())
        return jsonify({"error": str(e), "message": "حدث خطأ أثناء البحث"}), 500
