package handlers

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"

	"go-speech/internal/cache"
	"go-speech/internal/logger"
	"go-speech/tts"
)

type TTSHandler struct {
	ttsService *tts.PiperService
	modelDir   string
	cache      *cache.Cache
}

func NewTTSHandler(piperPath, modelDir, ffmpegPath string, cacheInstance *cache.Cache) *TTSHandler {
	service := tts.NewPiperService(piperPath, modelDir, ffmpegPath)
	return &TTSHandler{
		ttsService: service,
		modelDir:   modelDir,
		cache:      cacheInstance,
	}
}

type TTSRequest struct {
	Text  string `json:"text"`
	Voice string `json:"voice"`
}

func (h *TTSHandler) HandleTTS(w http.ResponseWriter, r *http.Request) {
	logger.Debug("=== Обработка TTS запроса ===")

	if r.Method != http.MethodPost {
		logger.Warn("Неподдерживаемый метод: %s", r.Method)
		http.Error(w, "Метод не поддерживается. Используйте POST", http.StatusMethodNotAllowed)
		return
	}

	// Проверка Content-Type
	contentType := r.Header.Get("Content-Type")
	logger.Debug("Content-Type: %s", contentType)
	if contentType != "application/json" {
		logger.Warn("Неверный Content-Type: %s", contentType)
		http.Error(w, "Content-Type должен быть application/json", http.StatusBadRequest)
		return
	}

	// Чтение тела запроса
	bodyBytes, err := io.ReadAll(r.Body)
	if err != nil {
		logger.Error("Ошибка чтения тела запроса: %v", err)
		http.Error(w, "Ошибка чтения запроса: "+err.Error(), http.StatusBadRequest)
		return
	}
	logger.Debug("Тело запроса: %s", string(bodyBytes))

	var req TTSRequest
	if err := json.Unmarshal(bodyBytes, &req); err != nil {
		logger.Error("Ошибка парсинга JSON: %v", err)
		http.Error(w, "Неверный формат JSON: "+err.Error(), http.StatusBadRequest)
		return
	}

	logger.Debug("Распарсенный запрос:")
	logger.Debug("  Text: %s (длина: %d)", req.Text, len(req.Text))
	logger.Debug("  Voice: %s", req.Voice)

	// Валидация текста
	if req.Text == "" {
		http.Error(w, "Поле 'text' не может быть пустым", http.StatusBadRequest)
		return
	}

	if len(req.Text) > 5000 {
		http.Error(w, "Текст слишком длинный (максимум 5000 символов)", http.StatusBadRequest)
		return
	}

	// Определение голоса (по умолчанию ruslan)
	voice := req.Voice
	if voice == "" {
		voice = "ruslan"
		logger.Debug("Голос не указан, используется по умолчанию: ruslan")
	}

	// Валидация голоса
	validVoices := map[string]bool{
		"ruslan": true,
		"irina":  true,
		"denis":  true,
		"dmitri": true,
	}
	if !validVoices[voice] {
		logger.Warn("Неверный голос: %s", voice)
		http.Error(w, "Неверный голос. Доступные: ruslan, irina, denis, dmitri", http.StatusBadRequest)
		return
	}
	logger.Debug("Выбранный голос: %s", voice)

	// Формируем имя модели для кэша
	modelName := fmt.Sprintf("ru_RU-%s-medium.onnx", voice)
	cacheKey := cache.GetCacheKey(modelName, req.Text)
	logger.Debug("Ключ кэша: %s", cacheKey)

	// Проверка кэша
	var audioPath string
	var tempFileToDelete string // Путь к временному файлу для удаления

	if h.cache != nil && h.cache.Exists(cacheKey) {
		logger.Debug("Файл найден в кэше, используем кэш")
		// Используем путь к файлу в кэше
		audioPath = h.cache.GetPath(cacheKey)
		logger.Debug("Используется файл из кэша: %s", audioPath)
	} else {
		// Генерация аудио
		logger.Debug("Файл не найден в кэше, начинаем генерацию...")
		logger.Debug("  Текст: %s", req.Text)
		logger.Debug("  Голос: %s", voice)
		generatedPath, err := h.ttsService.GenerateAudio(req.Text, voice)
		if err != nil {
			logger.Error("Ошибка генерации аудио: %v", err)
			log.Printf("Ошибка генерации аудио: %v", err)
			http.Error(w, "Ошибка генерации аудио: "+err.Error(), http.StatusInternalServerError)
			return
		}
		audioPath = generatedPath
		tempFileToDelete = generatedPath // Сохраняем путь для удаления
		logger.Debug("Аудио успешно сгенерировано: %s", audioPath)

		// Сохранение в кэш
		if h.cache != nil {
			logger.Debug("Сохранение файла в кэш...")
			if err := h.cache.Put(cacheKey, audioPath); err != nil {
				logger.Warn("Ошибка сохранения в кэш: %v", err)
			} else {
				logger.Debug("Файл успешно сохранен в кэш")
			}
		}
	}

	// Удаляем временный файл только если он был сгенерирован (не из кэша)
	if tempFileToDelete != "" {
		defer func() {
			if err := os.Remove(tempFileToDelete); err != nil {
				logger.Warn("Ошибка удаления временного файла %s: %v", tempFileToDelete, err)
			} else {
				logger.Debug("Временный файл удален: %s", tempFileToDelete)
			}
		}()
	}

	// Открытие файла
	logger.Debug("Открытие аудио файла: %s", audioPath)
	audioFile, err := os.Open(audioPath)
	if err != nil {
		logger.Error("Ошибка открытия аудио файла: %v", err)
		log.Printf("Ошибка открытия аудио файла: %v", err)
		http.Error(w, "Ошибка чтения аудио файла", http.StatusInternalServerError)
		return
	}
	defer audioFile.Close()

	// Получение информации о файле
	fileInfo, err := audioFile.Stat()
	if err != nil {
		logger.Error("Ошибка получения информации о файле: %v", err)
		log.Printf("Ошибка получения информации о файле: %v", err)
		http.Error(w, "Ошибка чтения аудио файла", http.StatusInternalServerError)
		return
	}
	logger.Debug("Размер аудио файла: %d байт", fileInfo.Size())

	// Установка заголовков ответа
	logger.Debug("Установка HTTP заголовков ответа")
	w.Header().Set("Content-Type", "audio/ogg")
	w.Header().Set("Content-Length", fmt.Sprintf("%d", fileInfo.Size()))
	w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename=speech-%s.ogg", voice))
	w.Header().Set("Cache-Control", "no-cache")
	w.WriteHeader(http.StatusOK)
	logger.Debug("Отправка аудио файла клиенту...")

	// Отправка файла
	bytesWritten, err := io.Copy(w, audioFile)
	if err != nil {
		logger.Error("Ошибка отправки аудио файла: %v", err)
		log.Printf("Ошибка отправки аудио файла: %v", err)
		return
	}
	logger.Debug("Аудио файл успешно отправлен: %d байт", bytesWritten)
	logger.Debug("=== TTS запрос обработан успешно ===")
}

// HandleHealthz генерирует аудио файл со словом "Окей" и возвращает его
func (h *TTSHandler) HandleHealthz(w http.ResponseWriter, r *http.Request) {
	// Генерация аудио со словом "Окей" (используем голос по умолчанию ruslan)
	audioPath, err := h.ttsService.GenerateAudio("Окей", "ruslan")
	if err != nil {
		log.Printf("Ошибка генерации аудио для healthz: %v", err)
		http.Error(w, "Ошибка генерации аудио: "+err.Error(), http.StatusInternalServerError)
		return
	}
	defer os.Remove(audioPath) // Удаляем временный файл после отправки

	// Открытие файла
	audioFile, err := os.Open(audioPath)
	if err != nil {
		log.Printf("Ошибка открытия аудио файла: %v", err)
		http.Error(w, "Ошибка чтения аудио файла", http.StatusInternalServerError)
		return
	}
	defer audioFile.Close()

	// Получение информации о файле
	fileInfo, err := audioFile.Stat()
	if err != nil {
		log.Printf("Ошибка получения информации о файле: %v", err)
		http.Error(w, "Ошибка чтения аудио файла", http.StatusInternalServerError)
		return
	}

	// Установка заголовков ответа
	w.Header().Set("Content-Type", "audio/ogg")
	w.Header().Set("Content-Length", fmt.Sprintf("%d", fileInfo.Size()))
	w.Header().Set("Content-Disposition", "attachment; filename=healthz.ogg")
	w.WriteHeader(http.StatusOK)

	// Отправка файла
	if _, err := io.Copy(w, audioFile); err != nil {
		log.Printf("Ошибка отправки аудио файла: %v", err)
		return
	}
}
