package batch

import (
	"encoding/json"
	"fmt"
	"strings"

	"sub2api-cn-relay-manager/internal/probe"
	"sub2api-cn-relay-manager/internal/store/sqlite"
)

type ProjectionBadge struct {
	Kind  string `json:"kind"`
	Tone  string `json:"tone"`
	Label string `json:"label"`
}

type RunSummaryProjection struct {
	RunID          string          `json:"run_id"`
	State          string          `json:"state"`
	StateBadge     ProjectionBadge `json:"state_badge"`
	Mode           string          `json:"mode"`
	AccessMode     string          `json:"access_mode"`
	TotalItems     int             `json:"total_items"`
	CompletedItems int             `json:"completed_items"`
	ActiveItems    int             `json:"active_items"`
	DegradedItems  int             `json:"degraded_items"`
	BrokenItems    int             `json:"broken_items"`
	WarningItems   int             `json:"warning_items"`
	StartedAt      string          `json:"started_at"`
	FinishedAt     string          `json:"finished_at"`
	RecentWarnings []string        `json:"recent_warnings"`
}

type ItemSummaryProjection struct {
	ItemID                 string            `json:"item_id"`
	BaseURL                string            `json:"base_url"`
	ProviderID             string            `json:"provider_id"`
	APIKeyFingerprint      string            `json:"api_key_fingerprint"`
	RequestedModels        []string          `json:"requested_models"`
	CanonicalModelFamilies []string          `json:"canonical_model_families"`
	ResolvedSmokeModel     string            `json:"resolved_smoke_model"`
	CurrentStage           string            `json:"current_stage"`
	ConfirmationStatus     string            `json:"confirmation_status"`
	AccessStatus           string            `json:"access_status"`
	MatchedAccountState    string            `json:"matched_account_state"`
	AccountResolution      string            `json:"account_resolution"`
	ProvisionReused        bool              `json:"provision_reused"`
	RetryCount             int               `json:"retry_count"`
	LastRetryAt            string            `json:"last_retry_at"`
	AdvisoryMessages       []string          `json:"advisory_messages"`
	LastErrorStage         string            `json:"last_error_stage"`
	LastError              string            `json:"last_error"`
	Badges                 []ProjectionBadge `json:"badges"`
}

type EventProjection struct {
	EventID     string `json:"event_id"`
	EventType   string `json:"event_type"`
	Stage       string `json:"stage"`
	Attempt     int    `json:"attempt"`
	Message     string `json:"message"`
	PayloadJSON string `json:"payload_json"`
	CreatedAt   string `json:"created_at"`
}

type ItemDetailProjection struct {
	ItemSummaryProjection
	RawModels            []string                `json:"raw_models"`
	NormalizedModels     []string                `json:"normalized_models"`
	RecommendedModels    []string                `json:"recommended_models"`
	ReusedFromProviderID string                  `json:"reused_from_provider_id"`
	ReusedFromAccountID  *int64                  `json:"reused_from_account_id"`
	ChannelID            *int64                  `json:"channel_id"`
	AccountID            *int64                  `json:"account_id"`
	CapabilityProfile    probe.CapabilityProfile `json:"capability_profile"`
	Events               []EventProjection       `json:"events"`
}

func ProjectRunSummary(run sqlite.ImportRun) RunSummaryProjection {
	view := RunSummaryProjection{
		RunID:          run.RunID,
		State:          run.State,
		StateBadge:     runStateBadge(run.State),
		Mode:           run.Mode,
		AccessMode:     run.AccessMode,
		TotalItems:     run.TotalItems,
		CompletedItems: run.CompletedItems,
		ActiveItems:    run.ActiveItems,
		DegradedItems:  run.DegradedItems,
		BrokenItems:    run.BrokenItems,
		WarningItems:   run.WarningItems,
		StartedAt:      run.StartedAt,
		FinishedAt:     run.FinishedAt,
		RecentWarnings: []string{},
	}
	if run.WarningItems > 0 {
		view.RecentWarnings = append(view.RecentWarnings, fmt.Sprintf("该批次包含 %d 条 advisory item，建议检查 capability profile 与 retry 轨迹", run.WarningItems))
	}
	return view
}

func ProjectItemSummary(item sqlite.ImportRunItem) ItemSummaryProjection {
	view := ItemSummaryProjection{
		ItemID:                 item.ItemID,
		BaseURL:                item.BaseURL,
		ProviderID:             item.ProviderID,
		APIKeyFingerprint:      item.APIKeyFingerprint,
		RequestedModels:        parseJSONStringArray(item.RequestedModelsJSON),
		CanonicalModelFamilies: parseJSONStringArray(item.CanonicalFamiliesJSON),
		ResolvedSmokeModel:     item.ResolvedSmokeModel,
		CurrentStage:           item.CurrentStage,
		ConfirmationStatus:     item.ConfirmationStatus,
		AccessStatus:           item.AccessStatus,
		MatchedAccountState:    item.MatchedAccountState,
		AccountResolution:      item.AccountResolution,
		ProvisionReused:        item.ProvisionReused,
		RetryCount:             item.RetryCount,
		LastRetryAt:            item.LastRetryAt,
		AdvisoryMessages:       mapAdvisoryMessages(parseJSONStringArray(item.AdvisoryMessagesJSON)),
		LastErrorStage:         item.LastErrorStage,
		LastError:              item.LastError,
		Badges:                 []ProjectionBadge{},
	}

	if item.ProvisionReused {
		view.Badges = append(view.Badges, ProjectionBadge{Kind: "reused", Tone: "cyan", Label: "reused"})
	}
	if badge, ok := matchedAccountStateBadge(item.MatchedAccountState); ok {
		view.Badges = append(view.Badges, badge)
	}
	if badge, ok := accountResolutionBadge(item.AccountResolution); ok {
		view.Badges = append(view.Badges, badge)
	}

	return view
}

func ProjectItemDetail(item sqlite.ImportRunItem, events []sqlite.ImportRunItemEvent) (ItemDetailProjection, error) {
	view := ItemDetailProjection{
		ItemSummaryProjection: ProjectItemSummary(item),
		RawModels:             parseJSONStringArray(item.RawModelsJSON),
		NormalizedModels:      parseJSONStringArray(item.NormalizedModelsJSON),
		RecommendedModels:     parseJSONStringArray(item.RecommendedModelsJSON),
		ReusedFromProviderID:  item.ReusedFromProviderID,
		ReusedFromAccountID:   item.ReusedFromAccountID,
		ChannelID:             item.ChannelID,
		AccountID:             item.AccountID,
		CapabilityProfile:     probe.CapabilityProfile{},
		Events:                make([]EventProjection, 0, len(events)),
	}

	if payload := strings.TrimSpace(item.CapabilityProfileJSON); payload != "" {
		if err := json.Unmarshal([]byte(payload), &view.CapabilityProfile); err != nil {
			return ItemDetailProjection{}, fmt.Errorf("decode capability profile: %w", err)
		}
	}

	for _, event := range events {
		view.Events = append(view.Events, EventProjection{
			EventID:     event.EventID,
			EventType:   event.EventType,
			Stage:       event.Stage,
			Attempt:     event.Attempt,
			Message:     event.Message,
			PayloadJSON: event.PayloadJSON,
			CreatedAt:   event.CreatedAt,
		})
	}

	return view, nil
}

func parseJSONStringArray(raw string) []string {
	values := []string{}
	if err := json.Unmarshal([]byte(defaultJSONString(raw, "[]")), &values); err != nil {
		return []string{}
	}
	return values
}

func mapAdvisoryMessages(messages []string) []string {
	mapped := make([]string, 0, len(messages))
	for _, message := range messages {
		switch strings.TrimSpace(message) {
		case "responses_unsupported_but_chat_ok":
			mapped = append(mapped, "该上游不支持 /v1/responses，系统已自动回退到 /v1/chat/completions")
		case "initial_probe_race_expected":
			mapped = append(mapped, "账号创建后宿主异步探测尚未稳定，首次 /test 已按 advisory 处理")
		case "gateway_warmup_retry_succeeded":
			mapped = append(mapped, "初次调度出现 no available accounts，短暂重试后已恢复")
		case "provision_reused":
			mapped = append(mapped, "已检测到同 URL + 同模型家族 + 健康账号，系统直接复用已有 provider")
		case "patch_only_new_aliases":
			mapped = append(mapped, "模型属于已覆盖家族，仅补充别名映射与定价，不重复创建资源")
		case "duplicate_active_account":
			mapped = append(mapped, "该账号已存在且处于启用状态，本次未重复创建，直接复用")
		case "deprecated_account_reactivated":
			mapped = append(mapped, "该账号此前处于弃用/停用状态，本次已快速启用并重新确认")
		default:
			if trimmed := strings.TrimSpace(message); trimmed != "" {
				mapped = append(mapped, trimmed)
			}
		}
	}
	return mapped
}

func runStateBadge(state string) ProjectionBadge {
	switch strings.TrimSpace(state) {
	case string(RunStateRunning):
		return ProjectionBadge{Kind: "state", Tone: "blue", Label: "running"}
	case string(RunStateCompleted):
		return ProjectionBadge{Kind: "state", Tone: "green", Label: "completed"}
	case string(RunStateCompletedWithWarnings):
		return ProjectionBadge{Kind: "state", Tone: "yellow", Label: "warning"}
	case string(RunStateFailed):
		return ProjectionBadge{Kind: "state", Tone: "red", Label: "failed"}
	case string(RunStateCancelled):
		return ProjectionBadge{Kind: "state", Tone: "gray", Label: "cancelled"}
	default:
		return ProjectionBadge{Kind: "state", Tone: "gray", Label: strings.TrimSpace(state)}
	}
}

func matchedAccountStateBadge(state string) (ProjectionBadge, bool) {
	switch strings.TrimSpace(state) {
	case string(MatchedAccountStateActive):
		return ProjectionBadge{Kind: "matched_account_state", Tone: "green", Label: "已启用"}, true
	case string(MatchedAccountStateDisabled):
		return ProjectionBadge{Kind: "matched_account_state", Tone: "gray", Label: "已停用"}, true
	case string(MatchedAccountStateDeprecated):
		return ProjectionBadge{Kind: "matched_account_state", Tone: "yellow", Label: "已弃用"}, true
	case string(MatchedAccountStateBroken):
		return ProjectionBadge{Kind: "matched_account_state", Tone: "red", Label: "已损坏"}, true
	default:
		return ProjectionBadge{}, false
	}
}

func accountResolutionBadge(resolution string) (ProjectionBadge, bool) {
	switch strings.TrimSpace(resolution) {
	case string(AccountResolutionCreated):
		return ProjectionBadge{Kind: "account_resolution", Tone: "blue", Label: "新建"}, true
	case string(AccountResolutionReused):
		return ProjectionBadge{Kind: "account_resolution", Tone: "cyan", Label: "复用"}, true
	case string(AccountResolutionReactivated):
		return ProjectionBadge{Kind: "account_resolution", Tone: "green", Label: "已快速启用"}, true
	case string(AccountResolutionReplaced):
		return ProjectionBadge{Kind: "account_resolution", Tone: "red", Label: "已替换"}, true
	default:
		return ProjectionBadge{}, false
	}
}
