"""
Leads domain: capture interest in court suppliers and financing.
"""

import json
import secrets
from pathlib import Path

from quart import Blueprint, flash, g, jsonify, redirect, render_template, request, session, url_for

from ..auth.routes import (
    create_auth_token,
    create_user,
    get_user_by_email,
    get_user_by_id,
    get_valid_token,
    login_required,
    mark_token_used,
    update_user,
)
from ..core import (
    config,
    csrf_protect,
    execute,
    fetch_one,
    is_disposable_email,
    is_plausible_phone,
    send_email,
    utcnow_iso,
)
from ..i18n import get_translations

bp = Blueprint(
    "leads",
    __name__,
    template_folder=str(Path(__file__).parent / "templates"),
    url_prefix="/leads",
)


# =============================================================================
# Heat Score Calculation
# =============================================================================


def calculate_heat_score(form: dict) -> str:
    """Score lead readiness from form data. Returns 'hot', 'warm', or 'cool'."""
    score = 0
    if form.get("timeline") in ("asap", "3-6mo"):
        score += 3
    elif form.get("timeline") == "6-12mo":
        score += 1
    phase = form.get("location_status", "")
    if phase in ("permit_granted",):
        score += 4
    elif phase in ("lease_signed", "permit_pending"):
        score += 3
    elif phase in ("converting_existing", "permit_not_filed"):
        score += 2
    elif phase in ("location_found",):
        score += 1
    if form.get("financing_status") in ("self_funded", "loan_approved"):
        score += 3
    elif form.get("financing_status") == "seeking":
        score += 1
    if form.get("decision_process") == "solo":
        score += 2
    elif form.get("decision_process") == "partners":
        score += 1
    if form.get("previous_supplier_contact") == "received_quotes":
        score += 2
    budget = int(form.get("budget_estimate", 0) or 0)
    if budget >= 250000:
        score += 2
    elif budget >= 100000:
        score += 1
    if score >= 10:
        return "hot"
    if score >= 5:
        return "warm"
    return "cool"


# =============================================================================
# Routes
# =============================================================================


@bp.route("/suppliers", methods=["GET", "POST"])
@login_required
@csrf_protect
async def suppliers():
    if request.method == "POST":
        form = await request.form
        await execute(
            """INSERT INTO lead_requests
            (user_id, lead_type, location, court_count, budget_estimate, message, created_at)
            VALUES (?, 'supplier', ?, ?, ?, ?, ?)""",
            (
                g.user["id"],
                form.get("location", ""),
                form.get("court_count", 0),
                form.get("budget", 0),
                form.get("message", ""),
                utcnow_iso(),
            ),
        )
        # Notify admin
        await send_email(
            config.LEADS_EMAIL,
            f"New supplier lead from {g.user['email']}",
            f"<p>Location: {form.get('location')}<br>Courts: {form.get('court_count')}<br>Budget: {form.get('budget')}<br>Message: {form.get('message')}</p>",
        )
        _t = get_translations(g.get("lang", "en"))
        await flash(_t["flash_suppliers_success"], "success")
        return redirect(url_for("leads.suppliers"))

    # Pre-fill from latest scenario
    scenario = await fetch_one(
        "SELECT state_json FROM scenarios WHERE user_id = ? AND deleted_at IS NULL ORDER BY updated_at DESC LIMIT 1",
        (g.user["id"],),
    )
    prefill = {}
    if scenario:
        try:
            state = json.loads(scenario["state_json"])
            prefill["court_count"] = state.get("dblCourts", 0) + state.get("sglCourts", 0)
        except (json.JSONDecodeError, TypeError):
            pass

    return await render_template("suppliers.html", prefill=prefill)


@bp.route("/financing", methods=["GET", "POST"])
@login_required
@csrf_protect
async def financing():
    if request.method == "POST":
        form = await request.form
        await execute(
            """INSERT INTO lead_requests
            (user_id, lead_type, location, court_count, budget_estimate, message, created_at)
            VALUES (?, 'financing', ?, ?, ?, ?, ?)""",
            (
                g.user["id"],
                form.get("location", ""),
                form.get("court_count", 0),
                form.get("budget", 0),
                form.get("message", ""),
                utcnow_iso(),
            ),
        )
        await send_email(
            config.LEADS_EMAIL,
            f"New financing lead from {g.user['email']}",
            f"<p>Location: {form.get('location')}<br>Courts: {form.get('court_count')}<br>Budget: {form.get('budget')}<br>Message: {form.get('message')}</p>",
        )
        _t = get_translations(g.get("lang", "en"))
        await flash(_t["flash_financing_success"], "success")
        return redirect(url_for("leads.financing"))

    scenario = await fetch_one(
        "SELECT state_json FROM scenarios WHERE user_id = ? AND deleted_at IS NULL ORDER BY updated_at DESC LIMIT 1",
        (g.user["id"],),
    )
    prefill = {}
    if scenario:
        try:
            state = json.loads(scenario["state_json"])
            prefill["court_count"] = state.get("dblCourts", 0) + state.get("sglCourts", 0)
        except (json.JSONDecodeError, TypeError):
            pass

    return await render_template("financing.html", prefill=prefill)


def _get_quote_steps(lang: str) -> list:
    """Return translated QUOTE_STEPS for the given language."""
    t = get_translations(lang)
    return [
        {"n": 1, "title": t["q1_heading"], "required": ["facility_type"]},
        {"n": 2, "title": t["q2_heading"], "required": ["country"]},
        {"n": 3, "title": t["q3_heading"], "required": []},
        {"n": 4, "title": t["q4_heading"], "required": ["location_status"]},
        {"n": 5, "title": t["q5_heading"], "required": ["timeline"]},
        {"n": 6, "title": t["q6_heading"], "required": ["financing_status", "decision_process"]},
        {"n": 7, "title": t["q7_heading"], "required": ["stakeholder_type"]},
        {"n": 8, "title": t["q8_heading"], "required": ["services_needed"]},
        {
            "n": 9,
            "title": t["q9_heading"],
            "required": ["contact_name", "contact_email", "contact_phone"],
        },
    ]


def _parse_accumulated(form_or_args):
    """Parse accumulated JSON from form data or query args."""
    raw = form_or_args.get("_accumulated", "{}")
    try:
        return json.loads(raw)
    except (json.JSONDecodeError, TypeError):
        return {}


@bp.route("/quote/step/<int:step>", methods=["GET", "POST"])
@csrf_protect
async def quote_step(step):
    """HTMX endpoint — validate current step and return next step partial."""
    lang = g.get("lang", "en")
    steps = _get_quote_steps(lang)
    if step < 1 or step > len(steps):
        return "Invalid step", 400

    if request.method == "POST":
        form = await request.form
        accumulated = _parse_accumulated(form)
        # Merge current step's fields into accumulated
        for k, v in form.items():
            if k.startswith("_") or k == "csrf_token":
                continue
            if k == "services_needed":
                accumulated.setdefault("services_needed", [])
                if v not in accumulated["services_needed"]:
                    accumulated["services_needed"].append(v)
            else:
                accumulated[k] = v
        # Handle services_needed as getlist for checkboxes
        services = form.getlist("services_needed")
        if services:
            accumulated["services_needed"] = services

        # Validate required fields for current step
        step_def = steps[step - 1]
        errors = []
        for field in step_def["required"]:
            val = accumulated.get(field, "")
            if isinstance(val, str) and not val.strip():
                errors.append(field)
            elif not val:
                errors.append(field)
        if errors:
            return await render_template(
                f"partials/quote_step_{step}.html",
                data=accumulated,
                step=step,
                steps=steps,
                errors=errors,
            )
        # Return next step
        next_step = step + 1
        if next_step > len(steps):
            next_step = len(steps)
        return await render_template(
            f"partials/quote_step_{next_step}.html",
            data=accumulated,
            step=next_step,
            steps=steps,
            errors=[],
        )

    # GET — render requested step (for back navigation / dot clicks)
    accumulated = _parse_accumulated(request.args)
    return await render_template(
        f"partials/quote_step_{step}.html",
        data=accumulated,
        step=step,
        steps=steps,
        errors=[],
    )


@bp.route("/quote", methods=["GET", "POST"])
@csrf_protect
async def quote_request():
    """Multi-step quote wizard. No login required — guests provide contact info."""
    if request.method == "POST":
        is_json = request.content_type and "application/json" in request.content_type

        if is_json:
            form = await request.get_json()
            services = form.get("services_needed", [])
            if isinstance(services, str):
                services = [services]
        else:
            form = await request.form
            services = form.getlist("services_needed")

        # Validate mandatory fields — collect field names for inline error display
        field_errors = []
        if not form.get("country"):
            field_errors.append("country")
        if not form.get("timeline"):
            field_errors.append("timeline")
        if not form.get("stakeholder_type"):
            field_errors.append("stakeholder_type")
        if not form.get("contact_name", "").strip():
            field_errors.append("contact_name")
        contact_email_raw = form.get("contact_email", "").strip()
        if not contact_email_raw:
            field_errors.append("contact_email")
        elif is_disposable_email(contact_email_raw):
            field_errors.append("contact_email")
        contact_phone_raw = form.get("contact_phone", "").strip()
        if not contact_phone_raw:
            field_errors.append("contact_phone")
        elif not is_plausible_phone(contact_phone_raw):
            field_errors.append("contact_phone")
        if field_errors:
            if is_json:
                return jsonify({"ok": False, "errors": field_errors}), 422
            form_data = {
                k: v for k, v in form.items() if not k.startswith("_") and k != "csrf_token"
            }
            form_data["services_needed"] = services
            return await render_template(
                "quote_request.html",
                data=form_data,
                step=9,
                steps=_get_quote_steps(g.get("lang", "en")),
                errors=field_errors,
            )

        heat = calculate_heat_score(form)

        # Compute credit cost from heat tier
        from ..credits import HEAT_CREDIT_COSTS

        credit_cost = HEAT_CREDIT_COSTS.get(heat, HEAT_CREDIT_COSTS["cool"])

        services_json = json.dumps(services) if services else None

        user_id = g.user["id"] if g.user else None
        contact_email = form.get("contact_email", "").strip().lower()

        # Logged-in user with matching email → skip verification
        is_verified_user = g.user is not None and g.user["email"].lower() == contact_email
        status = "new" if is_verified_user else "pending_verification"

        lead_id = await execute(
            """INSERT INTO lead_requests
            (user_id, lead_type, court_count, budget_estimate,
             facility_type, glass_type, lighting_type, build_context,
             location, country, timeline, location_status,
             financing_status, wants_financing_help, decision_process,
             previous_supplier_contact, services_needed, additional_info,
             contact_name, contact_email, contact_phone, contact_company,
             stakeholder_type,
             heat_score, status, credit_cost, token, created_at, visible_from)
            VALUES (?, 'quote', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now', '+2 hours'))""",
            (
                user_id,
                form.get("court_count", 0),
                form.get("budget_estimate", 0),
                form.get("facility_type", ""),
                form.get("glass_type", ""),
                form.get("lighting_type", ""),
                form.get("build_context", ""),
                form.get("city", ""),
                form.get("country", ""),
                form.get("timeline", ""),
                form.get("location_status", ""),
                form.get("financing_status", ""),
                1 if form.get("wants_financing_help") else 0,
                form.get("decision_process", ""),
                form.get("previous_supplier_contact", ""),
                services_json,
                form.get("additional_info", ""),
                form.get("contact_name", ""),
                contact_email,
                form.get("contact_phone", ""),
                form.get("contact_company", ""),
                form.get("stakeholder_type", ""),
                heat,
                status,
                credit_cost,
                secrets.token_urlsafe(16),
                utcnow_iso(),
            ),
        )

        # Remove from nurture audience (stop drip emails)
        if config.RESEND_AUDIENCE_PLANNER and config.RESEND_API_KEY:
            try:
                import resend

                resend.api_key = config.RESEND_API_KEY
                resend.Contacts.remove(
                    audience_id=config.RESEND_AUDIENCE_PLANNER,
                    email=contact_email,
                )
            except Exception:
                pass  # Best-effort removal

        if is_verified_user:
            # Existing flow: notify admin immediately
            await send_email(
                config.LEADS_EMAIL,
                f"[{heat.upper()}] New quote request from {contact_email}",
                f"<p><b>Heat:</b> {heat}<br>"
                f"<b>Contact:</b> {form.get('contact_name')} &lt;{contact_email}&gt;<br>"
                f"<b>Stakeholder:</b> {form.get('stakeholder_type')}<br>"
                f"<b>Facility:</b> {form.get('facility_type')} / {form.get('court_count')} courts<br>"
                f"<b>Glass:</b> {form.get('glass_type')} | <b>Lighting:</b> {form.get('lighting_type')}<br>"
                f"<b>Phase:</b> {form.get('location_status')} | <b>Timeline:</b> {form.get('timeline')}<br>"
                f"<b>Financing:</b> {form.get('financing_status')} | <b>Budget:</b> {form.get('budget_estimate')}<br>"
                f"<b>City:</b> {form.get('city')} | <b>Country:</b> {form.get('country')}</p>",
            )

            if is_json:
                return jsonify({"ok": True, "heat": heat})

            return await render_template(
                "quote_submitted.html",
                heat=heat,
                court_count=form.get("court_count", ""),
                facility_type=form.get("facility_type", ""),
                country=form.get("country", ""),
                contact_email=contact_email,
            )

        # --- Verification needed ---
        # Get-or-create user for contact_email
        existing_user = await get_user_by_email(contact_email)
        if not existing_user:
            new_user_id = await create_user(contact_email)
        else:
            new_user_id = existing_user["id"]

        # Link lead to user if guest submission
        if user_id is None:
            await execute(
                "UPDATE lead_requests SET user_id = ? WHERE id = ?",
                (new_user_id, lead_id),
            )

        token = secrets.token_urlsafe(32)
        await create_auth_token(new_user_id, token, minutes=60)

        lead_token_row = await fetch_one("SELECT token FROM lead_requests WHERE id = ?", (lead_id,))
        lead_token = lead_token_row["token"]

        from ..worker import enqueue

        await enqueue(
            "send_quote_verification",
            {
                "email": contact_email,
                "token": token,
                "lead_id": lead_id,
                "lead_token": lead_token,
                "lang": g.get("lang", "en"),
                "contact_name": form.get("contact_name", ""),
                "facility_type": form.get("facility_type", ""),
                "court_count": form.get("court_count", ""),
                "country": form.get("country", ""),
            },
        )

        if is_json:
            return jsonify({"ok": True, "pending_verification": True})

        return await render_template(
            "quote_verify_sent.html",
            contact_email=contact_email,
        )

    # GET — render wizard shell with starting step
    data = {}
    start_step = 1
    venue = request.args.get("venue", "")
    if venue:
        data = {
            "facility_type": venue,
            "court_count": request.args.get("courts", ""),
            "glass_type": request.args.get("glass", ""),
            "lighting_type": request.args.get("lighting", ""),
            "country": request.args.get("country", ""),
            "budget_estimate": request.args.get("budget", ""),
        }
        start_step = 2  # skip project step, already filled
    return await render_template(
        "quote_request.html",
        data=data,
        step=start_step,
        steps=_get_quote_steps(g.get("lang", "en")),
    )


@bp.route("/verify")
async def verify_quote():
    """Verify email from quote submission — activates lead and logs user in."""
    token_str = request.args.get("token")
    lead_token = request.args.get("lead")

    _t = get_translations(g.get("lang", "en"))
    if not token_str or not lead_token:
        await flash(_t["flash_verify_invalid"], "error")
        return redirect(url_for("leads.quote_request"))

    # Validate token
    token_data = await get_valid_token(token_str)
    if not token_data:
        await flash(_t["flash_verify_expired"], "error")
        return redirect(url_for("leads.quote_request"))

    # Validate lead exists and is pending — look up by opaque token
    lead = await fetch_one(
        "SELECT * FROM lead_requests WHERE token = ? AND status = 'pending_verification'",
        (lead_token,),
    )
    if not lead:
        await flash(_t["flash_verify_invalid_lead"], "error")
        return redirect(url_for("leads.quote_request"))

    # Mark token used
    await mark_token_used(token_data["id"])

    # Compute credit cost and activate lead
    from ..credits import compute_credit_cost

    credit_cost = compute_credit_cost(dict(lead))
    now = utcnow_iso()
    await execute(
        "UPDATE lead_requests SET status = 'new', verified_at = ?, credit_cost = ?, visible_from = datetime('now', '+2 hours') WHERE id = ?",
        (now, credit_cost, lead["id"]),
    )

    # Set user name from contact_name if not already set
    user = await get_user_by_id(token_data["user_id"])
    if user and not user.get("name"):
        await update_user(token_data["user_id"], name=lead["contact_name"])

    # Log user in
    session.permanent = True
    session["user_id"] = token_data["user_id"]
    await update_user(token_data["user_id"], last_login_at=now)

    # Send admin notification (deferred from submission)
    heat = lead["heat_score"] or "cool"
    contact_email = lead["contact_email"]
    await send_email(
        config.LEADS_EMAIL,
        f"[{heat.upper()}] New quote request from {contact_email}",
        f"<p><b>Heat:</b> {heat}<br>"
        f"<b>Contact:</b> {lead['contact_name']} &lt;{contact_email}&gt;<br>"
        f"<b>Stakeholder:</b> {lead['stakeholder_type']}<br>"
        f"<b>Facility:</b> {lead['facility_type']} / {lead['court_count']} courts<br>"
        f"<b>Glass:</b> {lead['glass_type']} | <b>Lighting:</b> {lead['lighting_type']}<br>"
        f"<b>Phase:</b> {lead['location_status']} | <b>Timeline:</b> {lead['timeline']}<br>"
        f"<b>Financing:</b> {lead['financing_status']} | <b>Budget:</b> {lead['budget_estimate']}<br>"
        f"<b>City:</b> {lead['location']} | <b>Country:</b> {lead['country']}</p>",
    )

    # Send welcome email
    from ..worker import enqueue

    await enqueue("send_welcome", {"email": contact_email, "lang": g.get("lang", "en")})
    await enqueue("notify_matching_suppliers", {"lead_id": lead["id"], "lang": g.get("lang", "en")})

    return await render_template(
        "quote_submitted.html",
        heat=heat,
        court_count=lead["court_count"] or "",
        facility_type=lead["facility_type"] or "",
        country=lead["country"] or "",
        contact_email=contact_email,
    )
