"""Pipeline start/stop and SSE stream routes."""
from __future__ import annotations

import asyncio
import json
import os
import sys
import tempfile
from pathlib import Path
from typing import Optional

import requests
from fastapi import APIRouter, Form, HTTPException, UploadFile, File
from fastapi.responses import StreamingResponse

# Add parent dir (streamlit_monitor) to sys.path so runners are importable
_MONITOR_DIR = Path(__file__).resolve().parent.parent.parent.parent
if str(_MONITOR_DIR) not in sys.path:
    sys.path.insert(0, str(_MONITOR_DIR))

# Load parent .env
_PARENT_ENV = _MONITOR_DIR.parent / ".env"
if _PARENT_ENV.exists():
    for _line in _PARENT_ENV.read_text(encoding="utf-8").splitlines():
        _line = _line.strip()
        if _line and not _line.startswith("#") and "=" in _line:
            _k, _, _v = _line.partition("=")
            _k = _k.strip()
            if _k and _k not in os.environ:
                os.environ[_k] = _v.strip()

from runner import PipelineRunner
from ..session import get_or_create_session, STEPS
from ..event_processor import process_all_events

router = APIRouter()


def _normalize_domain_url(domain_url: str) -> str:
    url = domain_url.strip()
    if url and "://" not in url:
        url = "https://" + url
    return url


def _validate_domain_url(domain_url: str) -> tuple[bool, str, dict]:
    api_url = os.environ.get("SYSTEM_BUILDER_API_URL", "").strip()
    if not api_url:
        return False, "SYSTEM_BUILDER_API_URL is not set.", {}
    normalized = _normalize_domain_url(domain_url)
    try:
        resp = requests.post(api_url, json={"domain_url": normalized}, timeout=10)
        if resp.status_code == 200:
            return True, "", resp.json()
        try:
            body = resp.json()
            detail = (
                body.get("message")
                or (body.get("detail") or {}).get("message")
                or resp.text
            )
        except Exception:
            detail = resp.text
        return False, f"Domain validation failed: {detail}", {}
    except requests.exceptions.ConnectionError:
        return False, "Could not reach the domain-info API.", {}
    except requests.exceptions.Timeout:
        return False, "Domain-info API timed out.", {}
    except Exception as exc:
        return False, f"Domain validation error: {exc}", {}


@router.post("/sessions")
async def create_session_endpoint():
    from ..session import create_session
    sess = create_session()
    return {"session_id": sess.session_id}


@router.get("/sessions/{session_id}/state")
async def get_state(session_id: str):
    sess = get_or_create_session(session_id)
    process_all_events(sess)
    return sess.to_dict()


@router.get("/sessions/{session_id}/stream")
async def stream_events(session_id: str):
    sess = get_or_create_session(session_id)

    async def event_generator():
        # Send initial state immediately
        data = json.dumps(sess.to_dict())
        yield f"data: {data}\n\n"

        while True:
            process_all_events(sess)
            data = json.dumps(sess.to_dict())
            yield f"data: {data}\n\n"
            await asyncio.sleep(0.5)

    return StreamingResponse(
        event_generator(),
        media_type="text/event-stream",
        headers={
            "Cache-Control": "no-cache",
            "X-Accel-Buffering": "no",
            "Connection": "keep-alive",
        },
    )


@router.post("/sessions/{session_id}/pipeline/start")
async def start_pipeline(
    session_id: str,
    prompt: str = Form(""),
    domain: str = Form(""),
    domain_url: str = Form(""),
    run_id: Optional[str] = Form(None),
    file: Optional[UploadFile] = File(None),
):
    sess = get_or_create_session(session_id)

    if sess.status == "running":
        raise HTTPException(status_code=409, detail="Pipeline already running")

    db_info: dict = {}
    canonical_domain_url = _normalize_domain_url(domain_url) if domain_url and domain_url.strip() else ""
    if canonical_domain_url:
        ok, err_msg, db_info = _validate_domain_url(canonical_domain_url)
        if not ok:
            raise HTTPException(status_code=400, detail=err_msg)

    file_path: Optional[Path] = None
    if file and file.filename:
        suffix = Path(file.filename).suffix
        tmp = tempfile.NamedTemporaryFile(delete=False, suffix=suffix, prefix="dpg_upload_")
        tmp.write(await file.read())
        tmp.close()
        file_path = Path(tmp.name)

    sess.reset_pipeline(run_id)
    runner = PipelineRunner()
    runner.start(
        prompt=prompt or "",
        file_path=file_path,
        domain=domain or "",
        domain_url=canonical_domain_url,
        db_info=db_info,
    )
    sess.runner = runner
    sess.status = "running"
    return {"ok": True, "session_id": session_id}


@router.post("/sessions/{session_id}/pipeline/stop")
async def stop_pipeline(session_id: str):
    sess = get_or_create_session(session_id)
    if sess.runner:
        sess.runner.terminate()
    sess.status = "error"
    import time
    for key, _ in STEPS:
        s = sess.pipeline["steps"][key]
        if s["status"] == "running":
            s["status"] = "error"
            if s["start_time"]:
                s["duration_ms"] = (time.time() - s["start_time"]) * 1000
    return {"ok": True}
