package eino

import (
	"context"
	"fmt"
	"strings"

	"github.com/cloudwego/eino/compose"

	"github.com/hhs/camtalk/internal/ai/stt"
	"github.com/hhs/camtalk/internal/models"
	"github.com/hhs/camtalk/internal/trace"
	"github.com/hhs/camtalk/internal/util"
)

// NewSTTLambda 创建 STT Lambda 节点。
// 输入: PipelineInput → 输出: STTOutput
//
// 文本输入模式：跳过 STT，直接返回用户输入文本。
// 语音模式：调用 sttService.Recognize() 进行语音识别。
// 识别结果通过 Sender 发送 stt_result 到客户端。
func NewSTTLambda(sttService stt.Service) *compose.Lambda {
	return compose.InvokableLambda(func(ctx context.Context, input PipelineInput) (STTOutput, error) {
		log := trace.FromContext(ctx)
		sender := senderFromCtx(ctx)
		requestID := requestIDFromCtx(ctx)

		// 将输入元数据写入 State，供下游节点（History、Done）读取
		if state := stateFromCtx(ctx); state != nil {
			state.mu.Lock()
			state.SessionID = input.SessionID
			state.RequestID = input.RequestID
			state.ImageData = input.ImageData
			state.Scenario = input.Scenario
			state.DetailLevel = "low"
			state.Language = input.Language
			state.TTSEnabled = input.TTSEnabled
			state.mu.Unlock()
		}

		// 文本输入模式：跳过 STT
		if input.Text != "" {
			log.Debugw("text input mode, skipping stt",
				"text_len", len(input.Text),
				"text_preview", util.Truncate(input.Text, 50))

			// 发送 stt_result 保持前端消息流一致性
			if sender != nil {
				if err := sender.SendSTTResult(models.WsSTTResult{
					Type:      "stt_result",
					RequestID: requestID,
					Text:      input.Text,
					IsFinal:   true,
				}); err != nil {
					log.Errorw("send stt_result failed", "error", err)
				}
			}

			// 写入 State
			if state := stateFromCtx(ctx); state != nil {
				state.mu.Lock()
				state.TranscribedText = input.Text
				state.mu.Unlock()
			}

			return STTOutput{
				Text:      input.Text,
				Language:  input.Language,
				IsSkipped: true,
			}, nil
		}

		// 语音模式：解码音频
		if len(input.AudioData) == 0 {
			return STTOutput{}, fmt.Errorf("stt: no audio data provided")
		}

		log.Debugw("stt recognition started", "audio_bytes", len(input.AudioData))

		// 调用 STT 服务
		text, err := sttService.Recognize(ctx, input.AudioData, stt.Options{
			Encoding:   "pcm_s16le",
			SampleRate: 16000,
			Language:   input.Language,
		})
		if err != nil {
			log.Errorw("stt recognition failed", "error", err)
			if sender != nil {
				sender.SendError(models.WsError{
					Type:      "error",
					RequestID: requestID,
					Code:      "STT_ERROR",
					Message:   "语音识别失败: " + err.Error(),
				})
			}
			return STTOutput{}, fmt.Errorf("stt: recognize: %w", err)
		}

		// STT 返回空文本
		if strings.TrimSpace(text) == "" {
			log.Infow("stt returned empty text")
			text = "（未识别到语音）"
		}

		log.Debugw("stt recognition completed",
			"text_len", len(text),
			"text_preview", util.Truncate(text, 50))

		// 发送 stt_result
		if sender != nil {
			if err := sender.SendSTTResult(models.WsSTTResult{
				Type:      "stt_result",
				RequestID: requestID,
				Text:      text,
				IsFinal:   true,
			}); err != nil {
				log.Errorw("send stt_result failed", "error", err)
			}
		}

		// 写入 State
		if state := stateFromCtx(ctx); state != nil {
			state.mu.Lock()
			state.TranscribedText = text
			state.mu.Unlock()
		}

		return STTOutput{
			Text:      text,
			Language:  input.Language,
			IsSkipped: false,
		}, nil
	})
}

