package stt

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/gorilla/websocket"
	"go.uber.org/zap"
)

// DeepgramService 基于 Deepgram WebSocket API 的语音识别实现。
type DeepgramService struct {
	apiKey   string
	model    string
	endpoint string
	timeout  time.Duration
	logger   *zap.SugaredLogger
}

// NewDeepgramService 创建 Deepgram STT 服务。
// model、endpoint 由 config 层保证非空，timeoutSec 为 0 时默认 5 秒。
func NewDeepgramService(apiKey, model, endpoint string, timeoutSec int, logger *zap.SugaredLogger) *DeepgramService {
	timeout := time.Duration(timeoutSec) * time.Second
	if timeout <= 0 {
		timeout = 5 * time.Second
	}
	return &DeepgramService{
		apiKey:   apiKey,
		model:    model,
		endpoint: endpoint,
		timeout:  timeout,
		logger:   logger,
	}
}

// deepgramResponse Deepgram WebSocket 响应。
type deepgramResponse struct {
	Channel struct {
		Alternatives []struct {
			Transcript string  `json:"transcript"`
			Confidence float64 `json:"confidence"`
		} `json:"alternatives"`
	} `json:"channel"`
	IsFinal bool `json:"is_final"`
}

// Recognize 实现 stt.Service。通过 WebSocket 发送音频到 Deepgram，返回最终识别文本。
func (d *DeepgramService) Recognize(ctx context.Context, audio []byte, opts Options) (string, error) {
	if len(audio) == 0 {
		return "", fmt.Errorf("stt: empty audio")
	}

	// 构建 WebSocket URL，附带查询参数
	wsURL := d.buildURL(opts)

	// 总超时
	ctx, cancel := context.WithTimeout(ctx, d.timeout)
	defer cancel()

	// 建立 WebSocket 连接
	conn, _, err := websocket.DefaultDialer.DialContext(ctx, wsURL, http.Header{
		"Authorization": []string{"Token " + d.apiKey},
	})
	if err != nil {
		return "", fmt.Errorf("stt: connect deepgram: %w", err)
	}
	defer conn.Close()

	// 发送音频数据（一次性）
	if err := conn.WriteMessage(websocket.BinaryMessage, audio); err != nil {
		return "", fmt.Errorf("stt: send audio: %w", err)
	}

	// 发送 Close 消息通知服务端音频已发送完毕
	closeMsg := websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")
	_ = conn.WriteMessage(websocket.CloseMessage, closeMsg)

	// 读取识别结果
	var transcript strings.Builder
	for {
		_, message, err := conn.ReadMessage()
		if err != nil {
			// Close 帧是正常的结束信号
			if websocket.IsCloseError(err, websocket.CloseNormalClosure) {
				break
			}
			if websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure) {
				break
			}
			return "", fmt.Errorf("stt: read response: %w", err)
		}

		var resp deepgramResponse
		if err := json.Unmarshal(message, &resp); err != nil {
			d.logger.Warnw("stt: unmarshal response failed", "error", err)
			continue
		}

		// 只累积 final 结果，跳过中间结果
		if resp.IsFinal && len(resp.Channel.Alternatives) > 0 {
			text := strings.TrimSpace(resp.Channel.Alternatives[0].Transcript)
			if text != "" {
				transcript.WriteString(text)
			}
		}
	}

	return strings.TrimSpace(transcript.String()), nil
}

// buildURL 构建 Deepgram WebSocket URL，包含音频格式参数。
func (d *DeepgramService) buildURL(opts Options) string {
	u, _ := url.Parse(d.endpoint)

	encoding := opts.Encoding
	if encoding == "" {
		encoding = "pcm_s16le"
	}
	sampleRate := opts.SampleRate
	if sampleRate == 0 {
		sampleRate = 16000
	}
	language := opts.Language
	if language == "" {
		language = "zh-CN"
	}

	q := u.Query()
	q.Set("encoding", encoding)
	q.Set("sample_rate", fmt.Sprintf("%d", sampleRate))
	q.Set("language", language)
	q.Set("model", d.model)
	q.Set("punctuate", "true")
	u.RawQuery = q.Encode()

	return u.String()
}
