// service/avatar_service.go
package service

import (
	"api_bb/internal/repository"
	"api_bb/pkg/logger"
	"fmt"
	"io"
	"mime/multipart"
	"os"
	"path/filepath"
	"strings"
	"time"

	"go.uber.org/zap"
)

type AvatarService interface {
	UploadAvatar(userID uint, file multipart.File, header *multipart.FileHeader) (string, error)
	DeleteAvatar(userID uint) error
	GetAvatarPath(userID uint) (string, error)
	GetAvatarFile(filename string) ([]byte, string, error)
	ServeAvatarFile(w io.Writer, filename string) (string, error)
}

type avatarService struct {
	userRepo repository.UserRepository
	logger   logger.LoggerInterface
}

func NewAvatarService(userRepo repository.UserRepository, log logger.LoggerInterface) AvatarService {
	return &avatarService{
		userRepo: userRepo,
		logger:   log.With(zap.String("service", "avatar")),
	}
}

func (s *avatarService) UploadAvatar(userID uint, file multipart.File, header *multipart.FileHeader) (string, error) {
	// Проверяем пользователя
	user, err := s.userRepo.FindByID(userID)
	if err != nil {
		return "", fmt.Errorf("user not found")
	}

	// Создаем директорию для аватаров если не существует
	uploadDir := "./uploads/avatars"
	if err := os.MkdirAll(uploadDir, 0755); err != nil {
		return "", fmt.Errorf("failed to create upload directory: %v", err)
	}

	// Генерируем уникальное имя файла
	fileExt := filepath.Ext(header.Filename)
	fileName := fmt.Sprintf("avatar_%d_%d%s", userID, time.Now().Unix(), fileExt)
	filePath := filepath.Join(uploadDir, fileName)

	// Создаем файл
	dst, err := os.Create(filePath)
	if err != nil {
		return "", fmt.Errorf("failed to create file: %v", err)
	}
	defer dst.Close()

	// Копируем содержимое
	if _, err := io.Copy(dst, file); err != nil {
		return "", fmt.Errorf("failed to save file: %v", err)
	}

	// Удаляем старый аватар если существует
	if user.Avatar != "" {
		oldPath := strings.TrimPrefix(user.Avatar, "/")
		if _, err := os.Stat(oldPath); err == nil {
			os.Remove(oldPath)
		}
	}

	// Сохраняем путь в БД
	avatarPath := "/uploads/avatars/" + fileName
	if err := s.userRepo.UpdateAvatar(userID, avatarPath); err != nil {
		// Если не удалось сохранить в БД, удаляем загруженный файл
		os.Remove(filePath)
		return "", fmt.Errorf("failed to update avatar in database: %v", err)
	}

	return avatarPath, nil
}

func (s *avatarService) DeleteAvatar(userID uint) error {
	user, err := s.userRepo.FindByID(userID)
	if err != nil {
		return fmt.Errorf("user not found")
	}

	if user.Avatar == "" {
		return nil // Аватара нет, ничего не делаем
	}

	// Удаляем файл
	filePath := strings.TrimPrefix(user.Avatar, "/")
	if _, err := os.Stat(filePath); err == nil {
		if err := os.Remove(filePath); err != nil {
			s.logger.Warn("Failed to delete avatar file", zap.Error(err))
		}
	}

	// Очищаем поле в БД
	return s.userRepo.UpdateAvatar(userID, "")
}

func (s *avatarService) GetAvatarPath(userID uint) (string, error) {
	user, err := s.userRepo.FindByID(userID)
	if err != nil {
		return "", err
	}
	return user.Avatar, nil
}

func (s *avatarService) GetAvatarFile(filename string) ([]byte, string, error) {
	// Валидация имени файла
	if filename == "" || strings.Contains(filename, "..") || strings.Contains(filename, "/") {
		return nil, "", fmt.Errorf("invalid filename")
	}

	// Проверяем допустимые расширения
	allowedExts := map[string]string{
		".png":  "image/png",
		".jpg":  "image/jpeg",
		".jpeg": "image/jpeg",
		".gif":  "image/gif",
		".webp": "image/webp",
	}

	fileExt := strings.ToLower(filepath.Ext(filename))
	contentType, exists := allowedExts[fileExt]
	if !exists {
		return nil, "", fmt.Errorf("unsupported file format")
	}

	// Формируем путь к файлу
	filePath := filepath.Join("./uploads/avatars", filename)

	// Проверяем существование файла
	fileInfo, err := os.Stat(filePath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, "", fmt.Errorf("avatar file not found")
		}
		return nil, "", fmt.Errorf("failed to access file: %v", err)
	}

	// Проверяем размер файла (максимум 10MB)
	if fileInfo.Size() > 10*1024*1024 {
		return nil, "", fmt.Errorf("file too large")
	}

	// Читаем файл
	fileData, err := os.ReadFile(filePath)
	if err != nil {
		return nil, "", fmt.Errorf("failed to read file: %v", err)
	}

	return fileData, contentType, nil
}

func (s *avatarService) ServeAvatarFile(w io.Writer, filename string) (string, error) {
	// Валидация имени файла
	if filename == "" || strings.Contains(filename, "..") || strings.Contains(filename, "/") {
		return "", fmt.Errorf("invalid filename")
	}

	// Проверяем допустимые расширения
	allowedExts := map[string]string{
		".png":  "image/png",
		".jpg":  "image/jpeg",
		".jpeg": "image/jpeg",
		".gif":  "image/gif",
		".webp": "image/webp",
	}

	fileExt := strings.ToLower(filepath.Ext(filename))
	contentType, exists := allowedExts[fileExt]
	if !exists {
		return "", fmt.Errorf("unsupported file format")
	}

	// Формируем путь к файлу
	filePath := filepath.Join("./uploads/avatars", filename)

	// Проверяем существование файла
	fileInfo, err := os.Stat(filePath)
	if err != nil {
		if os.IsNotExist(err) {
			return "", fmt.Errorf("avatar file not found")
		}
		return "", fmt.Errorf("failed to access file: %v", err)
	}

	// Проверяем размер файла
	if fileInfo.Size() > 10*1024*1024 {
		return "", fmt.Errorf("file too large")
	}

	// Открываем и копируем файл
	file, err := os.Open(filePath)
	if err != nil {
		return "", fmt.Errorf("failed to open file: %v", err)
	}
	defer file.Close()

	_, err = io.Copy(w, file)
	if err != nil {
		return "", fmt.Errorf("failed to serve file: %v", err)
	}

	return contentType, nil
}
