package worker

import (
	"context"
	"net/http"
	"strings"
	"testing"
	"time"
)

// TestClassifyDramaErrorTreatsTimeoutAsUpstreamFailure 验证超时不会再进入提交未知状态。
func TestClassifyDramaErrorTreatsTimeoutAsUpstreamFailure(t *testing.T) {
	if code := classifyDramaError(context.DeadlineExceeded); code != "upstream_timeout" {
		t.Fatalf("timeout code = %q, want upstream_timeout", code)
	}
}

// TestDramaModelRetryLimit 验证剧本解析调用的自动重试次数。
func TestDramaModelRetryLimit(t *testing.T) {
	if maxDramaModelAttempts != 5 {
		t.Fatalf("retry attempts = %d, want 5", maxDramaModelAttempts)
	}
}

func TestDramaHTTPClientAllowsLongTextResponses(t *testing.T) {
	sharedTransport := &http.Transport{TLSHandshakeTimeout: 10 * time.Second, ResponseHeaderTimeout: time.Minute}
	shared := &http.Client{Transport: sharedTransport}
	client := dramaHTTPClient(shared)
	transport, ok := client.Transport.(*http.Transport)
	if !ok {
		t.Fatal("drama client transport was not preserved")
	}
	if transport.TLSHandshakeTimeout != 30*time.Second || transport.ResponseHeaderTimeout != 10*time.Minute {
		t.Fatalf("unexpected drama timeouts: TLS=%s response=%s", transport.TLSHandshakeTimeout, transport.ResponseHeaderTimeout)
	}
	if sharedTransport.TLSHandshakeTimeout != 10*time.Second || sharedTransport.ResponseHeaderTimeout != time.Minute {
		t.Fatal("shared AI transport was modified")
	}
}

func TestParseDramaJSONNormalizesStoryboard(t *testing.T) {
	result, err := parseDramaJSON("<think>hidden</think>```json\n{\"entities\":{\"roles\":[{\"name\":\"林夏\",\"image_prompt\":\"二十五岁女性，黑色长发\"}]},\"storyboards\":[{\"content\":\"走进房间\",\"duration_seconds\":99}]}\n```")
	if err != nil {
		t.Fatalf("parseDramaJSON returned error: %v", err)
	}
	if len(result.Entities.Characters) != 1 || len(result.Storyboards) != 1 {
		t.Fatalf("unexpected normalized result: %#v", result)
	}
	if result.Storyboards[0].ScriptContent != "走进房间" || result.Storyboards[0].DurationSeconds != 5 {
		t.Fatalf("storyboard was not normalized: %#v", result.Storyboards[0])
	}
	if result.Entities.Characters[0].ImagePrompt != "二十五岁女性，黑色长发" {
		t.Fatalf("asset image prompt was not preserved: %#v", result.Entities.Characters[0])
	}
}

func TestEstimateTextTokens(t *testing.T) {
	if estimateTextTokens("中文ABCD") != 3 {
		t.Fatalf("unexpected token estimate")
	}
}

func TestBuildDramaUserPromptUsesOnlyCurrentContext(t *testing.T) {
	snapshot := dramaParseSnapshot{
		ProjectName: "测试项目",
		StyleName:   "国风水墨",
		EraType:     "ancient_xianxia",
		EpisodeNo:   4,
		EpisodeName: "再入山门",
	}
	prompt := buildDramaUserPrompt(snapshot, "当前集正文", []map[string]any{{"name": "林夏"}})
	for _, expected := range []string{
		"视觉风格：国风水墨",
		"故事时代：古代仙侠",
		"项目资产：",
		"林夏",
		"当前原文：\n当前集正文",
		"按上述视觉风格和故事时代解析角色、场景、道具及分镜",
	} {
		if !strings.Contains(prompt, expected) {
			t.Fatalf("prompt does not contain %q: %s", expected, prompt)
		}
	}
	for _, forbidden := range []string{"continuity", "解析分段", "前序"} {
		if strings.Contains(prompt, forbidden) {
			t.Fatalf("prompt contains forbidden content %q: %s", forbidden, prompt)
		}
	}
}

func TestDramaEraNameUsesCustomEra(t *testing.T) {
	if got := dramaEraName("other", "  民国时期  "); got != "民国时期" {
		t.Fatalf("unexpected custom era: %q", got)
	}
}
