package tts

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"go-speech/internal/logger"
)

type PiperService struct {
	piperPath  string
	modelDir   string
	ffmpegPath string
	tempDir    string
}

func NewPiperService(piperPath, modelDir, ffmpegPath string) *PiperService {
	tempDir := filepath.Join(os.TempDir(), "go-speech")
	os.MkdirAll(tempDir, 0755)

	return &PiperService{
		piperPath:  piperPath,
		modelDir:   modelDir,
		ffmpegPath: ffmpegPath,
		tempDir:    tempDir,
	}
}

// GenerateAudio генерирует аудио файл из текста и возвращает путь к OGG файлу
func (s *PiperService) GenerateAudio(text string, voice string) (string, error) {
	logger.Debug("=== Генерация аудио ===")
	logger.Debug("Параметры:")
	logger.Debug("  Текст: %s (длина: %d символов)", text, len(text))
	logger.Debug("  Голос: %s", voice)
	logger.Debug("  Piper путь: %s", s.piperPath)
	logger.Debug("  Директория моделей: %s", s.modelDir)
	logger.Debug("  FFmpeg путь: %s", s.ffmpegPath)
	logger.Debug("  Временная директория: %s", s.tempDir)

	// Формируем путь к модели на основе голоса
	modelFile := fmt.Sprintf("ru_RU-%s-medium.onnx", voice)
	modelPath := filepath.Join(s.modelDir, modelFile)
	logger.Debug("Путь к модели: %s", modelPath)

	// Создание уникального имени файла
	timestamp := time.Now().UnixNano()
	wavPath := filepath.Join(s.tempDir, fmt.Sprintf("speech_%d.wav", timestamp))
	oggPath := filepath.Join(s.tempDir, fmt.Sprintf("speech_%d.ogg", timestamp))
	logger.Debug("Временные файлы:")
	logger.Debug("  WAV: %s", wavPath)
	logger.Debug("  OGG: %s", oggPath)

	// Проверка наличия Piper
	logger.Debug("Проверка наличия Piper TTS...")
	if _, err := os.Stat(s.piperPath); os.IsNotExist(err) {
		logger.Error("Piper TTS не найден по пути: %s", s.piperPath)
		return "", fmt.Errorf("Piper TTS не найден по пути: %s", s.piperPath)
	}
	logger.Debug("Piper TTS найден")

	// Проверка наличия модели
	logger.Debug("Проверка наличия модели...")
	if _, err := os.Stat(modelPath); os.IsNotExist(err) {
		logger.Error("Модель не найдена по пути: %s", modelPath)
		return "", fmt.Errorf("Модель не найдена по пути: %s", modelPath)
	}
	logger.Debug("Модель найдена")

	// Генерация WAV файла через Piper
	logger.Debug("Запуск Piper TTS для генерации WAV...")
	cmd := exec.Command(s.piperPath,
		"--model", modelPath,
		"--output_file", wavPath,
	)
	logger.Debug("Команда Piper: %s --model %s --output_file %s", s.piperPath, modelPath, wavPath)

	// Получение stdin pipe для передачи текста
	logger.Debug("Создание stdin pipe...")
	stdin, err := cmd.StdinPipe()
	if err != nil {
		logger.Error("Ошибка создания stdin pipe: %v", err)
		return "", fmt.Errorf("ошибка создания stdin pipe: %v", err)
	}

	// Запуск команды
	logger.Debug("Запуск процесса Piper...")
	if err := cmd.Start(); err != nil {
		logger.Error("Ошибка запуска Piper: %v", err)
		return "", fmt.Errorf("ошибка запуска Piper: %v", err)
	}
	logger.Debug("Процесс Piper запущен (PID: %d)", cmd.Process.Pid)

	// Отправка текста в Piper через stdin
	logger.Debug("Отправка текста в Piper через stdin...")
	textToSend := text + "\n"
	if _, err := stdin.Write([]byte(textToSend)); err != nil {
		stdin.Close()
		cmd.Wait()
		logger.Error("Ошибка записи текста в Piper: %v", err)
		return "", fmt.Errorf("ошибка записи текста в Piper: %v", err)
	}
	logger.Debug("Текст отправлен (%d байт)", len(textToSend))
	stdin.Close()

	// Ожидание завершения Piper
	logger.Debug("Ожидание завершения Piper...")
	startTime := time.Now()
	if err := cmd.Wait(); err != nil {
		logger.Error("Ошибка выполнения Piper: %v", err)
		return "", fmt.Errorf("ошибка выполнения Piper: %v", err)
	}
	duration := time.Since(startTime)
	logger.Debug("Piper завершился успешно за %v", duration)

	// Проверка наличия созданного WAV файла
	logger.Debug("Проверка наличия WAV файла...")
	fileInfo, err := os.Stat(wavPath)
	if os.IsNotExist(err) {
		logger.Error("WAV файл не был создан")
		return "", fmt.Errorf("WAV файл не был создан")
	}
	logger.Debug("WAV файл создан: %d байт", fileInfo.Size())

	// Конвертация WAV в OGG через ffmpeg
	logger.Debug("Начало конвертации WAV в OGG через ffmpeg...")
	if err := s.convertToOGG(wavPath, oggPath); err != nil {
		logger.Error("Ошибка конвертации в OGG: %v", err)
		os.Remove(wavPath) // Удаляем WAV файл при ошибке
		return "", fmt.Errorf("ошибка конвертации в OGG: %v", err)
	}

	// Проверка размера OGG файла
	oggInfo, err := os.Stat(oggPath)
	if err == nil {
		logger.Debug("OGG файл создан: %d байт", oggInfo.Size())
		logger.Debug("Сжатие: %.2f%% (WAV: %d байт -> OGG: %d байт)",
			float64(fileInfo.Size()-oggInfo.Size())/float64(fileInfo.Size())*100,
			fileInfo.Size(), oggInfo.Size())
	}

	// Удаляем временный WAV файл
	logger.Debug("Удаление временного WAV файла...")
	if err := os.Remove(wavPath); err != nil {
		logger.Warn("Ошибка удаления WAV файла: %v", err)
	} else {
		logger.Debug("WAV файл удален")
	}

	logger.Debug("=== Генерация аудио завершена успешно ===")
	return oggPath, nil
}

// convertToOGG конвертирует WAV файл в OGG используя ffmpeg
func (s *PiperService) convertToOGG(wavPath, oggPath string) error {
	logger.Debug("=== Конвертация WAV в OGG ===")
	logger.Debug("Входной файл: %s", wavPath)
	logger.Debug("Выходной файл: %s", oggPath)

	// Проверка наличия ffmpeg
	logger.Debug("Проверка наличия ffmpeg...")
	if _, err := os.Stat(s.ffmpegPath); os.IsNotExist(err) {
		logger.Error("ffmpeg не найден по пути: %s", s.ffmpegPath)
		return fmt.Errorf("ffmpeg не найден по пути: %s", s.ffmpegPath)
	}
	logger.Debug("ffmpeg найден: %s", s.ffmpegPath)

	cmd := exec.Command(s.ffmpegPath,
		"-i", wavPath,
		"-acodec", "libvorbis",
		"-qscale:a", "5",
		"-y", // Перезаписать выходной файл если существует
		oggPath,
	)
	logger.Debug("Команда ffmpeg: %s -i %s -acodec libvorbis -qscale:a 5 -y %s",
		s.ffmpegPath, wavPath, oggPath)

	logger.Debug("Запуск ffmpeg...")
	startTime := time.Now()
	output, err := cmd.CombinedOutput()
	duration := time.Since(startTime)

	if err != nil {
		logger.Error("Ошибка выполнения ffmpeg: %v", err)
		logger.Debug("Вывод ffmpeg: %s", string(output))
		return fmt.Errorf("ошибка выполнения ffmpeg: %v, вывод: %s", err, string(output))
	}
	logger.Debug("ffmpeg завершился успешно за %v", duration)
	if len(output) > 0 {
		logger.Debug("Вывод ffmpeg: %s", string(output))
	}

	// Проверка наличия созданного OGG файла
	logger.Debug("Проверка наличия OGG файла...")
	if _, err := os.Stat(oggPath); os.IsNotExist(err) {
		logger.Error("OGG файл не был создан")
		return fmt.Errorf("OGG файл не был создан")
	}
	logger.Debug("OGG файл успешно создан")
	logger.Debug("=== Конвертация завершена ===")

	return nil
}
