// Package storage gère la persistance des fichiers PDF sur le disque.
package storage

import (
	"fmt"
	"io"
	"os"
	"path/filepath"

	"github.com/google/uuid"
)

// Store écrit et lit les fichiers PDF sous un dossier racine.
type Store struct {
	root string
}

// New crée un Store en s'assurant que le dossier racine existe.
func New(root string) (*Store, error) {
	if err := os.MkdirAll(root, 0o750); err != nil {
		return nil, fmt.Errorf("création du dossier de stockage : %w", err)
	}
	return &Store{root: root}, nil
}

// path retourne le chemin absolu d'un fichier à partir de son identifiant.
func (s *Store) path(id string) string {
	return filepath.Join(s.root, id)
}

// Save écrit le contenu de r dans un nouveau fichier et retourne son identifiant
// ainsi que le nombre d'octets écrits.
func (s *Store) Save(r io.Reader) (id string, size int64, err error) {
	id = uuid.NewString()
	f, err := os.OpenFile(s.path(id), os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0o640)
	if err != nil {
		return "", 0, err
	}
	defer f.Close()

	size, err = io.Copy(f, r)
	if err != nil {
		_ = os.Remove(s.path(id))
		return "", 0, err
	}
	return id, size, nil
}

// Overwrite remplace le contenu du fichier identifié par id.
func (s *Store) Overwrite(id string, r io.Reader) (size int64, err error) {
	f, err := os.OpenFile(s.path(id), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o640)
	if err != nil {
		return 0, err
	}
	defer f.Close()
	return io.Copy(f, r)
}

// Open ouvre le fichier identifié par id en lecture.
func (s *Store) Open(id string) (*os.File, error) {
	return os.Open(s.path(id))
}

// Delete supprime le fichier identifié par id. L'absence du fichier n'est pas une erreur.
func (s *Store) Delete(id string) error {
	err := os.Remove(s.path(id))
	if err != nil && !os.IsNotExist(err) {
		return err
	}
	return nil
}
