package apimart

import (
	"context"
	"encoding/json"
	"errors"
	"net/http"
	"strings"

	"juhe-factory/api/internal/provider"
)

func (c Client) SubmitImage(ctx context.Context, baseURL, apiKey, requestID string, payload map[string]any) (provider.SubmitResult, error) {
	data, err := c.requestJSON(ctx, http.MethodPost, baseURL, "/images/generations", apiKey, requestID, payload)
	if err != nil {
		return provider.SubmitResult{}, err
	}
	result := provider.SubmitResult{Raw: append(json.RawMessage(nil), data...)}
	var decoded any
	if err := json.Unmarshal(data, &decoded); err != nil {
		return provider.SubmitResult{}, errors.New("中转站提交响应不是有效 JSON")
	}
	result.TaskID = findString(decoded, "task_id", "id", "request_id")
	result.URL = findURL(decoded)
	if result.TaskID == "" && result.URL == "" {
		return provider.SubmitResult{}, errors.New("中转站提交响应缺少任务 ID 或结果 URL")
	}
	return result, nil
}

// PollImage 通过 APIMart 统一任务接口查询图片生成状态和结果。
func (c Client) PollImage(ctx context.Context, baseURL, apiKey, taskID string) (provider.PollResult, error) {
	data, err := c.requestJSON(ctx, http.MethodGet, baseURL, "/tasks/"+taskID, apiKey, "", nil)
	if err != nil {
		return provider.PollResult{}, err
	}
	var decoded any
	if err := json.Unmarshal(data, &decoded); err != nil {
		return provider.PollResult{}, errors.New("中转站轮询响应不是有效 JSON")
	}
	status := strings.ToLower(findString(decoded, "task_status", "status", "state"))
	if status == "" {
		status = "processing"
	}
	return provider.PollResult{Status: status, URL: findURL(decoded), Error: findString(decoded, "error_message", "error", "message", "detail"), Raw: append(json.RawMessage(nil), data...)}, nil
}

func findURL(value any) string {
	var walk func(any, string) string
	walk = func(node any, parentKey string) string {
		switch data := node.(type) {
		case string:
			if (strings.Contains(strings.ToLower(parentKey), "url") || strings.HasPrefix(data, "http://") || strings.HasPrefix(data, "https://")) && (strings.HasPrefix(data, "https://") || strings.HasPrefix(data, "http://")) {
				return data
			}
		case map[string]any:
			for key, child := range data {
				if found := walk(child, key); found != "" {
					return found
				}
			}
		case []any:
			for _, child := range data {
				if found := walk(child, parentKey); found != "" {
					return found
				}
			}
		}
		return ""
	}
	return walk(value, "")
}

func findString(value any, keys ...string) string {
	wanted := map[string]bool{}
	for _, key := range keys {
		wanted[strings.ToLower(key)] = true
	}
	return findMatchingString(value, func(key, _ string) bool { return wanted[strings.ToLower(key)] })
}

func findMatchingString(value any, match func(key, value string) bool) string {
	switch data := value.(type) {
	case map[string]any:
		for key, child := range data {
			if text, ok := child.(string); ok && match(key, text) {
				return text
			}
		}
		for _, child := range data {
			if found := findMatchingString(child, match); found != "" {
				return found
			}
		}
	case []any:
		for _, child := range data {
			if found := findMatchingString(child, match); found != "" {
				return found
			}
		}
	}
	return ""
}
