package rest_http

import (
	"bytes"
	"encoding/json"
	"io"
	"log"
	"mime/multipart"
	"net/http"
	"net/textproto"

	mjson "git.ali33.ru/fcg-xvii/go-tools/json"
	"git.ali33.ru/fcg-xvii/rest"
)

func NewResponse() *Response {
	return &Response{
		data:  make(mjson.Map),
		files: make(map[string]rest.IReadCloserLen),
	}
}

// Response реализует объект ответа
type Response struct {
	data  mjson.Map
	files map[string]rest.IReadCloserLen
	err   rest.IErrorArgs
	code  int
}

func (s *Response) IsError() bool {
	return s.err != nil
}

// KeySet устанавливает значение в словаре ответа по ключу
func (s *Response) KeySet(key string, val any) {
	s.data[key] = val
}

// FileSet устанавливает файл в словаре файлов по ключу
func (s *Response) FileSet(name string, file rest.IReadCloserLen) {
	s.files[name] = file
}

// Close закрывает ресурсы ответа после завершения отдачи серверу
func (s *Response) Close() {
	for _, file := range s.files {
		file.Close()
	}
}

// Send отправляет запрос серверу
func (s *Response) Send(writer any) rest.IErrorArgs {
	w := writer.(http.ResponseWriter)
	log.Println("SEND...")
	defer s.Close()
	if s.IsError() {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(s.code)
		w.Write([]byte(s.err.Error()))
		return nil
	}
	// Если есть файлы, то используем multipart
	if len(s.files) > 0 {
		var b bytes.Buffer
		writer := multipart.NewWriter(&b)
		w.Header().Set("Content-Type", writer.FormDataContentType())

		// Добавляем JSON-данные как часть
		partHeader := make(textproto.MIMEHeader)
		partHeader.Set("Content-Type", "application/json")
		partHeader.Set("Content-Disposition", `form-data; name="data"`)
		dataPart, err := writer.CreatePart(partHeader)
		if err != nil {
			return rest.ErrorMessage("ErrResponsePartDataCreate", err.Error())
		}
		if err := json.NewEncoder(dataPart).Encode(s.data); err != nil {
			return rest.ErrorMessage("ErrResponseDataJsonEncode", err.Error())
		}

		// Добавляем файлы
		for filename, file := range s.files {
			part, err := writer.CreateFormFile("file", filename)
			if err != nil {
				return rest.ErrorMessage("ErrResponsePartFileCreate", err.Error())
			}
			if _, err := io.Copy(part, file); err != nil {
				return rest.ErrorMessage("ErrResponsePartFileCopy", err.Error())
			}
		}

		// Закрываем multipart writer
		if err := writer.Close(); err != nil {
			return rest.ErrorMessage("ErrResponsePartFileClose", err.Error())
		}

		// Отправляем multipart response
		w.Header().Set("Content-Type", writer.FormDataContentType())
		w.Write(b.Bytes())
	} else {
		// Если нет файлов, просто отправляем JSON
		w.Header().Set("Content-Type", "application/json")
		if err := json.NewEncoder(w).Encode(s.data); err != nil {
			return rest.ErrorMessage("ErrResponseDataJsonEncode", err.Error())
		}
	}

	return nil
}

// Успрешный ответ

func ResponseSuccess(data mjson.Map, files map[string]rest.IReadCloserLen) *Response {
	return &Response{
		code:  200,
		data:  data,
		files: files,
	}
}

func ResponseError(code int, err rest.IErrorArgs) *Response {
	return &Response{
		code: code,
		err:  err,
	}
}
