// claude_api — 呼叫 Mira daemon（Hetzner 上跑的 Claude Agent SDK 服務）
//
// 架構決策（2026-05-06）：
// 不直打 Anthropic Messages API（OAuth token 限制 system prompt 角色 → rate_limit_error）
// 改透過已部署的 cloud-cto Mira daemon (https://mira.uncle6.me/mira/execute)
// 該 daemon 用 Claude Agent SDK，已內建 Mira persona，可長執行任務
//
// SDD: polaris/mira/.agents/specs/mira-app/design.md §6（五個 P0 零件）
//
//go:build tinygo

package main

import (
	"encoding/json"
	"io"
	"os"
	"unsafe"
)

//go:wasmimport u6u http_request
func hostHttpRequest(
	urlPtr uintptr, urlLen uint32,
	methodPtr uintptr, methodLen uint32,
	headersPtr uintptr, headersLen uint32,
	bodyPtr uintptr, bodyLen uint32,
	outPtr uintptr, outLenPtr uintptr,
) uint32

type Input struct {
	MiraURL     string `json:"mira_url"`     // 預設 https://mira.uncle6.me
	MiraToken   string `json:"mira_token"`   // Mira daemon Bearer token
	Prompt      string `json:"prompt"`       // 必填：要傳給 Mira 的訊息
	TimeoutMS   int    `json:"timeout_ms"`   // 預設 25000（daemon 協商模式上限）
	Model       string `json:"model"`        // 'haiku' / 'sonnet' / 'opus'，預設 haiku（daemon 端）
	CallbackURL string `json:"callback_url"` // optional：daemon 完成 task 時 POST 此 URL 通知（Resumable workflow，SDD: resumable-workflow）
}

var dummy [1]byte

func safePtr(b []byte) (uintptr, uint32) {
	if len(b) == 0 {
		return uintptr(unsafe.Pointer(&dummy[0])), 0
	}
	return uintptr(unsafe.Pointer(&b[0])), uint32(len(b))
}

func main() {
	raw, err := io.ReadAll(os.Stdin)
	if err != nil {
		writeError("failed to read stdin: " + err.Error())
		return
	}

	var input Input
	if err := json.Unmarshal(raw, &input); err != nil {
		writeError("invalid input JSON: " + err.Error())
		return
	}

	if input.MiraToken == "" {
		writeError("mira_token 必填（Mira daemon Bearer token）")
		return
	}
	if input.Prompt == "" {
		writeError("prompt 必填")
		return
	}

	miraURL := input.MiraURL
	if miraURL == "" {
		miraURL = "https://mira.uncle6.me"
	}
	timeoutMS := input.TimeoutMS
	if timeoutMS <= 0 {
		// 預設 120s：daemon 協商期會在 25s 切非同步 + callback；
		// callback_url 存在時，timeout 上限不重要（daemon 會 fire callback 不論多久）
		timeoutMS = 120000
	}

	// Mira daemon /execute 介面
	body := map[string]interface{}{
		"prompt":     input.Prompt,
		"timeout_ms": timeoutMS,
	}
	if input.Model != "" {
		body["model"] = input.Model
	}
	if input.CallbackURL != "" {
		body["callback_url"] = input.CallbackURL
	}
	bodyBytes, _ := json.Marshal(body)

	headers := map[string]string{
		"Content-Type":  "application/json",
		"Authorization": "Bearer " + input.MiraToken,
	}
	headersBytes, _ := json.Marshal(headers)

	url := miraURL + "/mira/execute"
	urlBytes := []byte(url)
	methodBytes := []byte("POST")

	outBuf := make([]byte, 1024*1024) // 1MB
	var outLen uint32

	urlPtr, urlLen := safePtr(urlBytes)
	methodPtr, methodLen := safePtr(methodBytes)
	headersPtr, headersLen := safePtr(headersBytes)
	bodyPtr, bodyLenU := safePtr(bodyBytes)

	result := hostHttpRequest(
		urlPtr, urlLen,
		methodPtr, methodLen,
		headersPtr, headersLen,
		bodyPtr, bodyLenU,
		uintptr(unsafe.Pointer(&outBuf[0])), uintptr(unsafe.Pointer(&outLen)),
	)

	if result != 0 {
		writeError("Mira daemon request failed (host_http_request returned non-zero)")
		return
	}

	respStr := string(outBuf[:outLen])
	var resp map[string]interface{}
	if err := json.Unmarshal([]byte(respStr), &resp); err != nil {
		writeError("Mira returned non-JSON: " + respStr)
		return
	}

	// 偵測錯誤回應
	if errObj, hasErr := resp["error"]; hasErr {
		errBytes, _ := json.Marshal(errObj)
		writeError("Mira error: " + string(errBytes))
		return
	}

	// daemon 回應格式：
	// 同步完成： {"task_id":"...","status":"done","output":"...","model":"..."}
	// 非同步：   {"task_id":"...","status":"running","estimated_seconds":N}

	status, _ := resp["status"].(string)
	if status == "running" {
		// 還沒完成，回傳 task_id 給 caller 自己 polling
		out, _ := json.Marshal(map[string]interface{}{
			"success":            true,
			"pending":            true,
			"task_id":            resp["task_id"],
			"estimated_seconds":  resp["estimated_seconds"],
			"poll_url":           miraURL + "/mira/execute/" + toString(resp["task_id"]),
		})
		os.Stdout.Write(out)
		return
	}

	// status == "done" 的場景
	out := map[string]interface{}{
		"success": true,
		"data": map[string]interface{}{
			"text":    resp["output"],
			"task_id": resp["task_id"],
			"model":   resp["model"],
		},
	}
	outJSON, _ := json.Marshal(out)
	os.Stdout.Write(outJSON)
}

func toString(v interface{}) string {
	if s, ok := v.(string); ok {
		return s
	}
	return ""
}

func writeError(msg string) {
	out, _ := json.Marshal(map[string]interface{}{"success": false, "error": msg})
	os.Stdout.Write(out)
}
