package files

import (
	"bytes"
	"fmt"
	"io/fs"
	"strings"
	"text/template"

	"git.perx.ru/perxis/perxis-go/pkg/id"
)

const (
	TemporaryPrefix = "tmp"
)

// File - описание файла в системе хранения perxis
type File struct {
	ID       string  `mapstructure:"id,omitempty" json:"id"`                                       // Уникальный идентификатор файла в хранилище
	Name     string  `mapstructure:"name,omitempty" json:"name" bson:"name,omitempty"`             // Имя файла
	Size     int     `mapstructure:"size,omitempty" json:"size" bson:"size,omitempty"`             // Размер файла
	MimeType string  `mapstructure:"mimeType,omitempty" json:"mimeType" bson:"mimeType,omitempty"` // Mime-type файла
	URL      string  `mapstructure:"url,omitempty" json:"url" bson:"url,omitempty"`                // Адрес для загрузки файла
	Key      string  `mapstructure:"key,omitempty" json:"key" bson:"key,omitempty"`                // Ключ для хранения файла в хранилище
	File     fs.File `mapstructure:"-" json:"-" bson:"-"`                                          // Файл для загрузки(из файловой системы)
}

func (f File) Clone() *File {
	return &f
}

func (f File) Temporary() bool {
	return strings.HasPrefix(f.ID, TemporaryPrefix)
}

func (f *File) SetURLWithTemplate(t *template.Template) error {
	if t == nil {
		return nil
	}

	res := new(bytes.Buffer)
	if err := t.Execute(res, f); err != nil {
		return err
	}

	f.URL = res.String()
	return nil
}

func (f File) ToExprMap() map[string]interface{} {
	return map[string]interface{}{
		"id":        f.ID,
		"name":      f.Name,
		"size":      f.Size,
		"mime_type": f.MimeType,
		"url":       f.URL,
		"key":       f.Key,
	}
}

func NewFile(name, mimeType string, size int, temp bool) *File {
	i := id.GenerateNewID()
	if temp {
		i = fmt.Sprintf("%s%s", TemporaryPrefix, i)
	}
	return &File{
		ID:       i,
		Name:     name,
		Size:     size,
		MimeType: mimeType,
	}
}

// MultipartUpload - описание загрузки файла
type MultipartUpload struct {
	File
	UploadID string           `json:"upload_id"` // Идентификатор загрузки хранилища
	PartSize int              `json:"part_size"` // Размер блока для загрузки
	PartURLs []string         `json:"part_urls"` // Адреса для загрузки полного файла
	Parts    []*CompletedPart `json:"parts"`     // Идентификаторы загруженных блоков (S3 ETAGs)
}

// Upload - описание загрузки файла
type Upload struct {
	File
	UploadURL string `json:"upload_url"` // Идентификатор загрузки хранилища
}

type CompletedPart struct {
	Number int    `json:"part_number"`
	ID     string `json:"id"`
}

func (u MultipartUpload) Clone() *MultipartUpload {
	return &u
}