#!/usr/bin/env bash
# Kiro local helper (macOS)
# Runs a LOCAL server on http://localhost:3128.
# It never reads passwords, cookies, browser session, and never stores tokens.
set -euo pipefail

PORT="3128"
PANEL="https://painel.conectai.site"

echo "Kiro local helper — http://localhost:${PORT}"
echo "Nenhuma senha, cookie ou sessao sera lida ou salva."

if ! command -v python3 >/dev/null 2>&1; then
  echo "ERRO: python3 nao encontrado. Instale o Python 3 e tente novamente." >&2
  exit 1
fi

KIRO_HELPER_PORT="${PORT}" KIRO_PANEL_URL="${PANEL}" python3 - <<'KIRO_PY'
import os, json, hashlib, base64, sqlite3, urllib.request, urllib.parse
from http.server import BaseHTTPRequestHandler, HTTPServer

PORT = int(os.environ.get("KIRO_HELPER_PORT", "3128"))
PANEL = os.environ.get("KIRO_PANEL_URL", "http://localhost:3000").rstrip("/")
IMPORT_COMPLETE_URL = PANEL + "/api/kiro-local/import-complete"
VERSION = "1.0.0"

# In-memory only. Maps sourceId -> parsed credential (incl. tokens). Never
# written to disk, never logged, never printed.
SOURCES = {}

def home():
    return os.path.expanduser("~")

def short_id(text):
    return hashlib.sha256(text.encode("utf-8")).hexdigest()[:12]

def candidate_paths():
    h = home()
    appdata = os.environ.get("APPDATA", "")
    localappdata = os.environ.get("LOCALAPPDATA", "")
    items = [
        ("KIRO_IDE_JSON", os.path.join(h, ".aws", "sso", "cache", "kiro-auth-token.json")),
        ("KIRO_CLI_SQLITE", os.path.join(h, "Library", "Application Support", "kiro-cli", "data.sqlite3")),
        ("KIRO_CLI_SQLITE", os.path.join(h, ".local", "share", "kiro-cli", "data.sqlite3")),
        ("AMAZON_Q_SQLITE", os.path.join(h, "Library", "Application Support", "amazon-q", "data.sqlite3")),
        ("AMAZON_Q_SQLITE", os.path.join(h, ".local", "share", "amazon-q", "data.sqlite3")),
    ]
    if appdata:
        items.append(("KIRO_CLI_SQLITE", os.path.join(appdata, "kiro-cli", "data.sqlite3")))
        items.append(("AMAZON_Q_SQLITE", os.path.join(appdata, "amazon-q", "data.sqlite3")))
    if localappdata:
        items.append(("KIRO_CLI_SQLITE", os.path.join(localappdata, "kiro-cli", "data.sqlite3")))
    return items

def pick(d, *names):
    for n in names:
        if isinstance(d, dict) and d.get(n) not in (None, ""):
            return d.get(n)
    return None

def decode_jwt_email(access_token):
    # Local, signature-less decode purely to surface the account email.
    try:
        parts = access_token.split(".")
        if len(parts) < 2:
            return None
        payload = parts[1]
        payload += "=" * (-len(payload) % 4)
        data = json.loads(base64.urlsafe_b64decode(payload).decode("utf-8", "ignore"))
        return pick(data, "email", "sub")
    except Exception:
        return None

def classify_auth_type(cred):
    if cred.get("clientId") and cred.get("clientSecret"):
        return "AWS_SSO_OIDC"
    provider = (cred.get("providerName") or cred.get("authMethod") or "").lower()
    if provider in ("google", "github", "social", "kiro"):
        return "KIRO_SOCIAL"
    if cred.get("startUrl"):
        return "BUILDER_ID"
    return "KIRO_DESKTOP" if cred.get("refreshToken") else "UNKNOWN"

def normalize(raw, source):
    cred = {
        "source": source,
        "accessToken": pick(raw, "accessToken", "access_token"),
        "refreshToken": pick(raw, "refreshToken", "refresh_token"),
        "expiresAt": pick(raw, "expiresAt", "expires_at"),
        "region": pick(raw, "region") or "us-east-1",
        "profileArn": pick(raw, "profileArn", "profile_arn"),
        "clientId": pick(raw, "clientId", "client_id"),
        "clientSecret": pick(raw, "clientSecret", "client_secret"),
        "startUrl": pick(raw, "startUrl", "start_url"),
        "providerName": pick(raw, "provider", "providerName", "authMethod"),
    }
    cred["authType"] = classify_auth_type(cred)
    email = None
    if cred["accessToken"]:
        email = decode_jwt_email(cred["accessToken"])
    cred["accountEmail"] = email
    return cred

def parse_kiro_ide_json(path):
    try:
        with open(path, "r", encoding="utf-8") as f:
            raw = json.load(f)
        return [normalize(raw, "KIRO_IDE_JSON")]
    except Exception:
        return []

TOKEN_KEYS = [
    "kirocli:social:token", "kirocli:odic:token", "kirocli:oidc:token",
    "codewhisperer:odic:token", "codewhisperer:oidc:token",
]

def parse_sqlite(path, source):
    creds = []
    try:
        conn = sqlite3.connect("file:%s?mode=ro" % path, uri=True)
        try:
            cur = conn.cursor()
            cur.execute("SELECT key, value FROM auth_kv")
            rows = cur.fetchall()
        finally:
            conn.close()
    except Exception:
        return creds
    for key, value in rows:
        if not any(tk in str(key) for tk in TOKEN_KEYS):
            continue
        try:
            raw = json.loads(value)
        except Exception:
            continue
        if isinstance(raw, dict):
            creds.append(normalize(raw, source))
    return creds

def scan():
    SOURCES.clear()
    results = []
    for source, path in candidate_paths():
        if not os.path.exists(path):
            continue
        if source == "KIRO_IDE_JSON":
            parsed = parse_kiro_ide_json(path)
        else:
            parsed = parse_sqlite(path, source)
        for cred in parsed:
            sid = short_id(path + "|" + (cred.get("accountEmail") or "") + "|" + source)
            cred["sourcePathHash"] = short_id(path)
            SOURCES[sid] = cred
            results.append({
                "id": sid,
                "source": source,
                "pathExists": True,
                "hasAccessToken": bool(cred.get("accessToken")),
                "hasRefreshToken": bool(cred.get("refreshToken")),
                "hasExpiresAt": bool(cred.get("expiresAt")),
                "hasProfileArn": bool(cred.get("profileArn")),
                "hasRegion": bool(cred.get("region")),
                "hasClientId": bool(cred.get("clientId")),
                "hasClientSecret": bool(cred.get("clientSecret")),
                "region": cred.get("region"),
                "expiresAt": cred.get("expiresAt"),
                "authType": cred.get("authType"),
                "providerName": cred.get("providerName"),
                "accountEmail": cred.get("accountEmail"),
                "canImport": bool(cred.get("refreshToken")),
            })
    return {"found": len(results) > 0, "sources": results}

def do_import(source_id, import_session_token):
    if not SOURCES:
        scan()
    cred = SOURCES.get(source_id)
    if not cred:
        return {"ok": False, "error": "source_not_found"}
    if not cred.get("refreshToken"):
        return {"ok": False, "error": "missing_refresh_token"}
    payload = {
        "importSessionToken": import_session_token,
        "source": cred.get("source"),
        "accessToken": cred.get("accessToken"),
        "refreshToken": cred.get("refreshToken"),
        "expiresAt": cred.get("expiresAt"),
        "region": cred.get("region") or "us-east-1",
        "profileArn": cred.get("profileArn"),
        "clientId": cred.get("clientId"),
        "clientSecret": cred.get("clientSecret"),
        "authType": cred.get("authType"),
        "providerName": cred.get("providerName"),
        "accountEmail": cred.get("accountEmail"),
        "sourcePathHash": cred.get("sourcePathHash"),
        "metadata": {"startUrl": cred.get("startUrl")},
    }
    try:
        body = json.dumps(payload).encode("utf-8")
        req = urllib.request.Request(IMPORT_COMPLETE_URL, data=body,
            headers={"Content-Type": "application/json"})
        resp = urllib.request.urlopen(req, timeout=15)
        raw = resp.read().decode("utf-8", "ignore")
        try:
            parsed = json.loads(raw)
        except Exception:
            parsed = {}
        return {"ok": True, "forwarded": True, "panel": parsed}
    except Exception:
        return {"ok": False, "forwarded": False, "error": "panel_unreachable"}

HELP_HTML = ("<!doctype html><html><head><meta charset='utf-8'><title>Kiro Local Helper</title>"
    "</head><body style='font-family:system-ui,sans-serif;background:#171717;color:#fff;"
    "padding:48px;max-width:640px;margin:auto'>"
    "<h2 style='color:#3ecf8e'>Helper Kiro local ativo.</h2>"
    "<p>Ele nao le senha, cookie ou sessao.</p>"
    "<p>Ele apenas localiza arquivos de credenciais ja criados pelo Kiro IDE/CLI apos login manual.</p>"
    "</body></html>")

def cors_headers(handler):
    handler.send_header("Access-Control-Allow-Origin", "*")
    handler.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
    handler.send_header("Access-Control-Allow-Headers", "Content-Type")

class Handler(BaseHTTPRequestHandler):
    def log_message(self, *args):
        return  # never log request lines (may include the one-time code)

    def _json(self, code, obj):
        body = json.dumps(obj).encode("utf-8")
        self.send_response(code)
        self.send_header("Content-Type", "application/json")
        cors_headers(self)
        self.end_headers()
        self.wfile.write(body)

    def _html(self, code, html):
        body = html.encode("utf-8")
        self.send_response(code)
        self.send_header("Content-Type", "text/html; charset=utf-8")
        cors_headers(self)
        self.end_headers()
        self.wfile.write(body)

    def do_OPTIONS(self):
        self.send_response(204)
        cors_headers(self)
        self.end_headers()

    def do_GET(self):
        parsed = urllib.parse.urlparse(self.path)
        if parsed.path == "/health":
            self._json(200, {"ok": True, "service": "kiro-local-helper", "port": PORT, "version": VERSION})
            return
        if parsed.path == "/scan-kiro-credentials":
            self._json(200, scan())
            return
        if parsed.path == "/oauth/callback":
            qs = urllib.parse.parse_qs(parsed.query)
            code = (qs.get("code") or [""])[0]
            state = (qs.get("state") or [""])[0]
            full_url = "http://localhost:%d/oauth/callback?%s" % (PORT, parsed.query)
            forwarded = False
            if code and state:
                try:
                    b = json.dumps({"code": code, "state": state}).encode("utf-8")
                    r = urllib.request.Request(PANEL + "/api/kiro-login/complete", data=b,
                        headers={"Content-Type": "application/json"})
                    urllib.request.urlopen(r, timeout=10).read()
                    forwarded = True
                except Exception:
                    forwarded = False
            msg = "<h2 style='color:#3ecf8e'>Login Kiro recebido com sucesso.</h2><p>Voce ja pode voltar ao painel.</p><p>Nenhuma senha, cookie ou sessao foi salva.</p>"
            if not forwarded:
                msg += "<p>Se o painel nao atualizar, copie e cole esta URL no campo manual:</p><code style='word-break:break-all'>" + full_url + "</code>"
            self._html(200, "<!doctype html><html><head><meta charset='utf-8'></head><body style='font-family:system-ui,sans-serif;background:#171717;color:#fff;padding:48px;max-width:640px;margin:auto'>" + msg + "</body></html>")
            return
        if parsed.path == "/":
            self._html(200, HELP_HTML)
            return
        self._json(404, {"ok": False, "error": "not_found"})

    def do_POST(self):
        parsed = urllib.parse.urlparse(self.path)
        if parsed.path != "/import-kiro-credentials":
            self._json(404, {"ok": False, "error": "not_found"})
            return
        length = int(self.headers.get("Content-Length", "0") or "0")
        try:
            data = json.loads(self.rfile.read(length).decode("utf-8", "ignore")) if length else {}
        except Exception:
            data = {}
        source_id = data.get("sourceId", "")
        import_session_token = data.get("importSessionToken", "")
        if not source_id or not import_session_token:
            self._json(400, {"ok": False, "error": "missing_source_or_session"})
            return
        self._json(200, do_import(source_id, import_session_token))

print("Helper Kiro local ouvindo em http://localhost:%d" % PORT)
print("Rotas: /health, /scan-kiro-credentials, /import-kiro-credentials, /oauth/callback")
print("Nao le nem salva senha, cookie, sessao ou token. Ctrl+C para encerrar.")
HTTPServer(("127.0.0.1", PORT), Handler).serve_forever()

KIRO_PY
