#!/bin/bash

# ==========================================
# Jiaotu Workflow v12.0 (JSON Escape Fix)
# ==========================================

ACCOUNTS_FILE="./accounts.txt"

# --- 日志工具 ---
log_info() { echo -e "\033[0;32m[INFO] $1\033[0m" >&2; }
log_warn() { echo -e "\033[0;33m[WARN] $1\033[0m" >&2; }
log_err() { echo -e "\033[0;31m[ERROR] $1\033[0m" >&2; }
log_step() { echo -e "\033[0;36m=== $1 ===\033[0m" >&2; }

# --- 帮助菜单 ---
show_usage() {
    cat <<EOF
Usage: $(basename "$0") [FLAGS...]
See script source for full documentation.
EOF
}

# --- 仅检查余额 ---
check_balance_only() {
    local C_TOKEN="$1"
    local C_SESSION="$2"
    C_TOKEN=$(echo "$C_TOKEN" | tr -d '\r\n ')
    C_SESSION=$(echo "$C_SESSION" | tr -d '\r\n ')

    curl -s 'https://api.jiaotuai.cn/api/v1/sign/check' \
      -H "Authorization: Bearer ${C_TOKEN}" \
      -H 'Content-Type: application/json' \
      -H 'User-Agent: Mozilla/5.0' -o /dev/null
    
    local RESP=$(curl -s 'https://api.jiaotuai.cn/api/v1/product/queryPackageCount' \
      -H "Authorization: Bearer ${C_TOKEN}" \
      -H 'Content-Type: application/json' \
      -H 'User-Agent: Mozilla/5.0' \
      -H "Referer: https://www.jiaotuai.cn/studio?sessionId=${C_SESSION}")
    
    local AVAIL=$(echo "$RESP" | grep -oE '"availableCount":[0-9]+' | grep -oE '[0-9]+' | head -n 1)
    echo "${AVAIL:-0}"
}

# --- 核心工作流 ---
jiaotu_workflow() {
    local TOKEN="$1"; shift
    local SESSION="$1"; shift
    TOKEN=$(echo "$TOKEN" | tr -d '\r\n ')
    SESSION=$(echo "$SESSION" | tr -d '\r\n ')

    local IMAGES_URLS=()
    local ELEMENT_URL=""
    local MODE_BIKINI=false
    local MODE_KISS=false
    local MODE_HUG=false
    local MODE_SCREENSHOT=false
    local MODE_CYRENE=false
    local MODE_CYRENE_POSE=false
    local CHAR_NAME=""
    local CONST_ID_BIKINI="2012598262529208321"
    local CONST_ID_CYRENE="2012623834793848833"

    while [[ $# -gt 0 ]]; do
        case "$1" in
            --img) if [[ -n "$2" && "$2" != --* ]]; then IMAGES_URLS+=("$2"); shift; fi ;;
            --element) if [[ -n "$2" ]]; then ELEMENT_URL="$2"; shift; fi ;;
            --name) if [[ -n "$2" ]]; then CHAR_NAME="$2"; shift; fi ;;
            --bikini) MODE_BIKINI=true ;;
            --kiss) MODE_KISS=true ;;
            --hug) MODE_HUG=true ;;
            --screenshot) MODE_SCREENSHOT=true ;;
            --cyrene) MODE_CYRENE=true ;;
            --cyrene-pose) MODE_CYRENE=true; MODE_CYRENE_POSE=true ;;
            *) if [[ "$1" == http* ]]; then IMAGES_URLS+=("$1"); fi ;;
        esac
        shift
    done

    if [[ "$MODE_CYRENE" == true && -z "$CHAR_NAME" ]]; then log_err "Cyrene模式需要 --name"; return 1; fi

    # Step 1
    log_step "Step 1: Account Confirmation"
    local POINTS=$(check_balance_only "$TOKEN" "$SESSION")
    log_info "Current Balance: $POINTS"
    
    # Step 2
    log_step "Step 2: Uploading Inputs"
    local UPLOADED_IDS=()
    
    upload_stream() {
        local TARGET_URL="$1"
        local VNAME="stream_$(date +%s)_$RANDOM.jpg"
        
        # 1. Token
        local BODY_T=$(printf '{"sessionId":"%s","fileName":"%s"}' "$SESSION" "$VNAME")
        local RESP_T=$(curl -s -X POST "https://api.jiaotuai.cn/api/v1/upload/token" \
            -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$BODY_T")
        
        local UP_URL=$(echo "$RESP_T" | sed -nE 's/.*"uploadUrl":"([^"]+)".*/\1/p')
        local CB_TOKEN=$(echo "$RESP_T" | sed -nE 's/.*"callbackToken":"([^"]+)".*/\1/p')
        
        if [[ -z "$UP_URL" ]]; then 
            log_err "获取上传链接失败: $TARGET_URL" >&2
            return 1
        fi
        
        # 2. Upload (Added -L for redirects, common with Wikia)
        log_info "正在流式传输: ${TARGET_URL:0:40}..." >&2
        local CODE=$(curl -L "$TARGET_URL" -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' 2>/dev/null \
            | curl -s -w "%{http_code}" -X PUT "$UP_URL" -H "Content-Type: image/jpeg" --data-binary @- -o /dev/null)
        
        if [[ "$CODE" != "200" ]]; then
            log_err "上传失败 HTTP $CODE: $TARGET_URL" >&2
            return 1
        fi
        
        # 3. Callback
        local BODY_C=$(printf '{"callbackToken":"%s","fileName":"%s"}' "$CB_TOKEN" "$VNAME")
        local RESP_C=$(curl -s -X POST "https://api.jiaotuai.cn/api/v1/upload/callback" \
            -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$BODY_C")
        
        # 严格提取 ID
        local RET_ID=$(echo "$RESP_C" | grep -oE '"(data|id|ossId)":"?[0-9]+' | grep -oE '[0-9]+' | head -n 1)
        
        if [[ -z "$RET_ID" ]]; then
            log_err "回调未返回ID。Response: $RESP_C" >&2
            return 1
        fi
        
        echo "$RET_ID"
    }

    # 上传主图
    for img in "${IMAGES_URLS[@]}"; do
        local uid=$(upload_stream "$img")
        if [[ -n "$uid" ]]; then
            UPLOADED_IDS+=("$uid")
            log_info "Uploaded ID: $uid"
        else
            log_err "主图上传失败，终止任务。"
            return 1
        fi
    done
    
    # 上传元素图
    local ELE_ID=""
    if [[ -n "$ELEMENT_URL" ]]; then
        ELE_ID=$(upload_stream "$ELEMENT_URL")
        # 严格检查，如果上传失败则报错
        if [[ -z "$ELE_ID" ]]; then 
            log_err "元素图上传失败，终止任务。"
            return 1
        fi
        log_info "Element ID: $ELE_ID"
    fi

    # Step 3
    log_step "Step 3: Constructing Prompt"
    local FINAL_PROMPT=""
    local FINAL_IDS_JSON=""

    if [[ "$MODE_CYRENE" == true ]]; then
        if [[ ${#UPLOADED_IDS[@]} -eq 0 ]]; then log_err "Need input image"; return 1; fi
        local VAR_ID="${UPLOADED_IDS[0]}"
        local IDS_STR="\"${VAR_ID}\",\"${CONST_ID_CYRENE}\""
        
        # [修复点] 将 \"${CHAR_NAME}\" 改为 '${CHAR_NAME}'，防止 JSON 截断
        FINAL_PROMPT="pls replace cyrene in the second pic with ${CHAR_NAME} in the first pic,\\nand make sure the character name in the second pic to be '${CHAR_NAME}',"

        if [[ "$MODE_CYRENE_POSE" == true ]]; then 
            FINAL_PROMPT="${FINAL_PROMPT}\\nand make sure ${CHAR_NAME} replicate the same pose, body posture, facial expression, and camera framing as cyrene. Keep the same angle, perspective, and composition, without any deviation,"
        fi
        
        if [[ -n "$ELE_ID" ]]; then 
            FINAL_PROMPT="${FINAL_PROMPT}\\nand replace ice icon in the pic with lightning icon in pic3,"
            IDS_STR="${IDS_STR},\"${ELE_ID}\""
        fi
        
        FINAL_PROMPT="${FINAL_PROMPT}\\nand make the other ui element in the second pic intact"
        FINAL_IDS_JSON="[${IDS_STR}]"
    else
        # Cosplay 模式逻辑 (保持不变)
        local CNT=${#UPLOADED_IDS[@]}
        if [[ $CNT -eq 0 ]]; then log_err "Need input image"; return 1; fi
        if [[ "$MODE_KISS" == true || "$MODE_HUG" == true ]]; then
            if [[ $CNT -ge 2 ]]; then FINAL_PROMPT="pic 1 is character A and pic 2 is character B,\\npls Generate a highly detailed realistic cosplay photo of character A and character B,\\n"; else FINAL_PROMPT="pls Generate a highly detailed realistic cosplay photo of girls in pic1,\\n"; fi
        else FINAL_PROMPT="pls Generate a highly detailed realistic cosplay photo of character(s) in pic1,\\n"; fi
        FINAL_PROMPT="${FINAL_PROMPT}and preserve [their] headband if [they] had any,\\n"
        local B_IDX=2; if [[ "$MODE_BIKINI" == true ]]; then if [[ $CNT -ge 2 ]]; then B_IDX=3; fi; FINAL_PROMPT="${FINAL_PROMPT}and then add [them] with strapless micro bikini with color matchin' [their] hair color and shape matchin' pic [${B_IDX}],\\n"; fi
        FINAL_PROMPT="${FINAL_PROMPT}and then add thin, metal frames in a round style glasses with transparent lens and frame color matchin' [their respective eye color] for [them],\\n"
        if [[ "$MODE_SCREENSHOT" == true ]]; then FINAL_PROMPT="${FINAL_PROMPT}and use the original background of [pic1], and make the ui elements of the original screenshot intact.\\n"; else FINAL_PROMPT="${FINAL_PROMPT}by a seaside beach.\\n"; fi
        FINAL_PROMPT="${FINAL_PROMPT}Keep [their] hair style as same as the original illustrations. Exactly replicate the same pose, body posture, hand gestures, facial expression, and camera framing as in the original illustrations. Keep the same angle, perspective, and composition, without any deviation,\\n"
        if [[ "$MODE_KISS" == true ]]; then FINAL_PROMPT="${FINAL_PROMPT}And make them do french kiss while holding hands,\\n"; elif [[ "$MODE_HUG" == true ]]; then FINAL_PROMPT="${FINAL_PROMPT}And make them hug each other but look at the camera,\\n"; fi
        FINAL_PROMPT="${FINAL_PROMPT}and make the aspect ratio of this pic to be 16:9."
        local IDS_STR=""; for id in "${UPLOADED_IDS[@]}"; do if [[ -z "$IDS_STR" ]]; then IDS_STR="\"$id\""; else IDS_STR="$IDS_STR,\"$id\""; fi; done
        if [[ "$MODE_BIKINI" == true ]]; then IDS_STR="$IDS_STR,\"${CONST_ID_BIKINI}\""; fi
        FINAL_IDS_JSON="[${IDS_STR}]"
    fi

    # Step 4
    log_step "Step 4: Generating"
    local POST_DATA="{\"prompt\":\"${FINAL_PROMPT}\",\"sessionId\":\"${SESSION}\",\"imagesIds\":${FINAL_IDS_JSON},\"size\":\"16:9\",\"qualityLevel\":\"4K\",\"modelId\":11}"
    
    local GEN_RES=$(curl -s -N 'https://api.jiaotuai.cn/api/v1/ai/imageChat' \
        --compressed -X POST -H 'User-Agent: Mozilla/5.0' -H 'Content-Type: application/json' \
        -H "Authorization: Bearer ${TOKEN}" -H "Referer: https://www.jiaotuai.cn/studio?sessionId=${SESSION}" \
        --data "${POST_DATA}")
    
    local GEN_ID=$(echo "$GEN_RES" | grep '"type":"image"' | sed -nE 's/.*"ossId":"([0-9]+)".*/\1/p' | tail -n 1)
    
    if [[ -z "$GEN_ID" ]]; then 
        log_err "Generation Failed"
        # 仅打印最后一行错误信息，避免刷屏
        echo "$GEN_RES" | tail -n 1 >&2 
        return 1
    fi
    log_info "Gen ID: $GEN_ID"

    # Step 5
    log_step "Step 5: Downloading"
    local URL_RES=$(curl -s "https://api.jiaotuai.cn/api/v1/imageSession/getImageUrl?ossId=${GEN_ID}&imageType=2" -H "Authorization: Bearer ${TOKEN}" -H "Referer: https://www.jiaotuai.cn/")
    local FINAL_URL=$(echo "$URL_RES" | sed -nE 's/.*"data":"([^"]+)".*/\1/p')
    if [[ -z "$FINAL_URL" ]]; then return 1; fi
    
    local SAVE_NAME="jiaotu_$(date +%Y%m%d_%H%M%S)_${GEN_ID}.jpg"
    if curl -s -o "$SAVE_NAME" "$FINAL_URL"; then
        log_info "Saved: $(pwd)/$SAVE_NAME"
    else
        log_err "Save failed."
    fi
    echo "$FINAL_URL"
}

# --- Main ---
main() {
    if [[ "$1" == "-h" || "$1" == "--help" ]]; then show_usage; return 0; fi
    if [[ ! -f "$ACCOUNTS_FILE" ]]; then log_err "File not found: $ACCOUNTS_FILE"; return 1; fi

    log_step "Initializing: Checking Account Pool..."
    local SELECTED_TOKEN=""
    local SELECTED_SESSION=""
    local ACCOUNT_INDEX=0

    while read -r line <&3 || [[ -n "$line" ]]; do
        [[ -z "$line" || "$line" == \#* ]] && continue
        ((ACCOUNT_INDEX++))
        
        local CUR_TOKEN=$(echo "$line" | awk '{print $1}' | tr -d '\r')
        local CUR_SESSION=$(echo "$line" | awk '{print $2}' | tr -d '\r')
        
        if [[ -z "$CUR_TOKEN" || -z "$CUR_SESSION" ]]; then continue; fi

        local POINTS=$(check_balance_only "$CUR_TOKEN" "$CUR_SESSION")
        if [[ "$POINTS" -ge 10 ]]; then
            log_info "✅ Account #$ACCOUNT_INDEX Selected! (Points: $POINTS)"
            SELECTED_TOKEN="$CUR_TOKEN"; SELECTED_SESSION="$CUR_SESSION"
            break
        else
            log_warn "❌ Account #$ACCOUNT_INDEX Insufficient Points ($POINTS). Trying next..."
        fi
    done 3< "$ACCOUNTS_FILE"

    if [[ -z "$SELECTED_TOKEN" ]]; then log_err "No available accounts."; return 1; fi
    
    log_step "Starting Workflow with Account #$ACCOUNT_INDEX"
    jiaotu_workflow "$SELECTED_TOKEN" "$SELECTED_SESSION" "$@"
}

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi