from fastapi import FastAPI, Request, Body, Header
from fastapi.middleware.cors import CORSMiddleware
from httpx import AsyncClient
from urllib.parse import urlunparse
from typing import Any, Dict

import json
import os


class config:
    HOST = os.environ.get("LOCALPROXY_HOST", "127.0.0.1")
    PORT = int(os.environ.get("LOCALPROXY_PORT", "13377"))
    # When set, replaces the inbound Authorization header on the upstream call.
    API_KEY = os.environ.get("LOCALPROXY_API_KEY", "")

print(f"Starting local proxy on {config.HOST}:{config.PORT}, forwarding to real OpenAI with API key: {config.API_KEY!r}")


app = FastAPI(docs_url=None)
http_client = AsyncClient()

# Set at module load when the GUI starts; the request handler emits through it.
_text_sink = None  # type: Any


def push_ui_text(text: str) -> None:
    if _text_sink is not None:
        _text_sink(text)


app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


@app.post("/{openai_path:path}")
async def request_handler(
    request: Request,
    openai_path: str,
    json_body: Dict[str, Any] = Body(...),
    x_real_domain: str = Header(alias="X-Real-Domain", default="api.openai.com"),
) -> Dict[str, Any]:
    url = urlunparse(("https", x_real_domain, openai_path, "", "", ""))

    auth = f"Bearer {config.API_KEY}" if config.API_KEY else request.headers.get("Authorization", "")

    resp = await http_client.post(
        url,
        json = json_body,
        headers = {"Authorization": auth},
    )
    data = resp.json()

    try:
        pretty = data["choices"][0]["message"]["content"]
    except Exception:
        try:
            pretty = json.dumps(data, indent=2, ensure_ascii=False)
        except Exception:
            pretty = str(data)

    push_ui_text(pretty)

    return {"ok": True}


if __name__ == "__main__":
    import sys
    import threading

    import uvicorn

    from PySide6.QtCore import QObject, Qt, Signal
    from PySide6.QtGui import QFont
    from PySide6.QtWidgets import QApplication, QMainWindow, QPlainTextEdit

    class TextBridge(QObject):
        # Signal carries text from any thread to the Qt main loop safely.
        received = Signal(str)

    class MainWindow(QMainWindow):
        def __init__(self, bridge: TextBridge) -> None:
            super().__init__()
            self.setWindowTitle("Response Viewer")
            self.resize(520, 400)

            self.view = QPlainTextEdit(self)
            self.view.setReadOnly(True)
            self.view.setFont(QFont("Consolas", 11))
            self.view.setLineWrapMode(QPlainTextEdit.LineWrapMode.WidgetWidth)
            self.view.setPlainText("Waiting for responses...")

            self.setCentralWidget(self.view)

            bridge.received.connect(self.view.setPlainText, Qt.ConnectionType.QueuedConnection)

    qt_app = QApplication(sys.argv)
    bridge = TextBridge()
    window = MainWindow(bridge)
    window.show()

    # Wire the FastAPI handler -> Qt signal. emit() is thread-safe with QueuedConnection.
    _text_sink = bridge.received.emit

    def run_server() -> None:
        uvicorn.run(app, host=config.HOST, port=config.PORT, log_level="info")

    threading.Thread(target=run_server, daemon=True).start()

    sys.exit(qt_app.exec())
