package stt

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"strings"
	"time"
)

// Whisper, whisper.cpp sunucusunun HTTP ucunu konuşur (yerel tanıma).
//
// Akış: multipart/form-data ile `file` alanında ses gönderilir, yanıttaki `text` okunur.
// Sunucu kapalıysa/500 dönerse hata geçici sayılır (WS katmanı "motor yanıt vermedi" der).
type Whisper struct {
	url      string
	language string
	client   *http.Client
}

// NewWhisper tanım oluşturur. URL boşsa nil döner (STT yapılandırılmamış demektir).
func NewWhisper(opt Options) *Whisper {
	if strings.TrimSpace(opt.URL) == "" {
		return nil
	}
	timeout := opt.Timeout
	if timeout <= 0 {
		timeout = 60 * time.Second
	}
	return &Whisper{
		url:      strings.TrimSpace(opt.URL),
		language: opt.Language,
		client:   &http.Client{Timeout: timeout},
	}
}

// Transcribe ses baytlarını metne çevirir.
func (w *Whisper) Transcribe(ctx context.Context, audio []byte, mime string) (string, error) {
	if w == nil {
		return "", ErrNoRecognizer
	}
	if len(audio) == 0 {
		return "", ErrEmptyAudio
	}
	if mime == "" {
		mime = "application/octet-stream"
	}

	var body bytes.Buffer
	mw := multipart.NewWriter(&body)
	part, err := mw.CreateFormFile("file", "audio"+extFor(mime))
	if err != nil {
		return "", err
	}
	if _, err := part.Write(audio); err != nil {
		return "", err
	}
	if w.language != "" {
		_ = mw.WriteField("language", w.language)
	}
	if err := mw.Close(); err != nil {
		return "", err
	}

	req, err := http.NewRequestWithContext(ctx, http.MethodPost, w.url, &body)
	if err != nil {
		return "", err
	}
	req.Header.Set("Content-Type", mw.FormDataContentType())

	resp, err := w.client.Do(req)
	if err != nil {
		return "", fmt.Errorf("%w: %v", ErrUnavailable, err)
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		raw, _ := io.ReadAll(io.LimitReader(resp.Body, 512))
		return "", fmt.Errorf("%w: HTTP %d: %s", ErrUnavailable, resp.StatusCode, strings.TrimSpace(string(raw)))
	}

	var out struct {
		Text string `json:"text"`
	}
	if err := json.NewDecoder(io.LimitReader(resp.Body, 1<<20)).Decode(&out); err != nil {
		return "", fmt.Errorf("%w: yanıt okunamadı: %v", ErrUnavailable, err)
	}
	return out.Text, nil
}

// extFor, içerik türünden dosya uzantısı üretir (whisper.cpp uzantıya bakar).
func extFor(mime string) string {
	switch {
	case strings.Contains(mime, "wav"):
		return ".wav"
	case strings.Contains(mime, "mpeg"), strings.Contains(mime, "mp3"):
		return ".mp3"
	case strings.Contains(mime, "ogg"):
		return ".ogg"
	case strings.Contains(mime, "webm"):
		return ".webm"
	case strings.Contains(mime, "mp4"):
		return ".m4a"
	default:
		return ".bin"
	}
}
