package infra

import (
	"bytes"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"strings"
)

// ParsedFile representa un archivo extraido de un multipart form, con su contenido
// completo en memoria y los primeros bytes (Header) listos para validacion por
// magic bytes.
type ParsedFile struct {
	FormField string // nombre del field del form (ej: "file", "image")
	Filename  string // nombre original reportado por el cliente
	Size      int64  // tamano en bytes
	MIMEHint  string // Content-Type segun el cliente (NO confiar — usar FileValidateType)
	Header    []byte // primeros 512 bytes para magic byte detection
	Content   io.Reader
}

// UploadParse parsea un request multipart/form-data y extrae todos los archivos
// adjuntos. Aplica http.MaxBytesReader para limitar el tamano total a maxSize bytes.
//
// Retorna un slice de ParsedFile con el contenido cargado en memoria como bytes.Reader,
// listo para ser pasado a FileSaveDisk o S3Upload.
//
// Para uploads muy grandes considerar streaming con multipart.Reader directamente
// en vez de esta funcion (que carga todo en memoria).
func UploadParse(r *http.Request, maxSize int64) ([]ParsedFile, error) {
	if r.Body == nil {
		return nil, fmt.Errorf("upload_parse: request sin body")
	}
	ct := r.Header.Get("Content-Type")
	if !strings.HasPrefix(ct, "multipart/") {
		return nil, fmt.Errorf("upload_parse: content-type %q no es multipart", ct)
	}

	r.Body = http.MaxBytesReader(nil, r.Body, maxSize)
	if err := r.ParseMultipartForm(maxSize); err != nil {
		return nil, fmt.Errorf("upload_parse: parse form: %w", err)
	}
	if r.MultipartForm == nil {
		return nil, fmt.Errorf("upload_parse: form vacio")
	}

	var out []ParsedFile
	for field, headers := range r.MultipartForm.File {
		for _, fh := range headers {
			pf, err := readMultipartFile(field, fh)
			if err != nil {
				return nil, err
			}
			out = append(out, pf)
		}
	}
	return out, nil
}

func readMultipartFile(field string, fh *multipart.FileHeader) (ParsedFile, error) {
	f, err := fh.Open()
	if err != nil {
		return ParsedFile{}, fmt.Errorf("upload_parse: open %s: %w", fh.Filename, err)
	}
	defer f.Close()

	buf, err := io.ReadAll(f)
	if err != nil {
		return ParsedFile{}, fmt.Errorf("upload_parse: read %s: %w", fh.Filename, err)
	}

	header := buf
	if len(header) > 512 {
		header = header[:512]
	}

	return ParsedFile{
		FormField: field,
		Filename:  fh.Filename,
		Size:      int64(len(buf)),
		MIMEHint:  fh.Header.Get("Content-Type"),
		Header:    header,
		Content:   bytes.NewReader(buf),
	}, nil
}
