package handler

import (
	"bytes"
	"encoding/json"
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	"gitstore.ru/tolikproh/sirius/internal/model"
)

const (
	MAX_UPLOAD_SIZE = 30 << 20 // 5 megabytes
)

var (
	JSON_TYPES = map[string]interface{}{
		"application/json":    nil,
		"text/json":           nil,
		"multipart/form-data": nil,
	}
)

type uploadResponse struct {
	Status string `json:"status"`
	Msg    string `json:"message,omitempty"`
	URL    string `json:"url,omitempty"`
}

func Upload(c *gin.Context) {
	// Limit Upload File Size
	c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, MAX_UPLOAD_SIZE)

	file, fileHeader, err := c.Request.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, &uploadResponse{
			Status: "error",
			Msg:    err.Error(),
		})
		return
	}

	defer file.Close()

	buffer := make([]byte, fileHeader.Size)
	file.Read(buffer)
	buffer = bytes.TrimPrefix(buffer, []byte("\xef\xbb\xbf"))
	fileType := http.DetectContentType(buffer)

	// Validate File Type
	if _, ex := JSON_TYPES[fileType]; !ex || !json.Valid(buffer) {
		c.JSON(http.StatusBadRequest, &uploadResponse{
			Status: "error",
			Msg:    "file type is not supported",
		})
		return
	}

	var sirius model.Sirius
	err = json.Unmarshal(buffer, &sirius)
	if err != nil {
		c.JSON(http.StatusBadRequest, &uploadResponse{
			Status: "error",
			Msg:    err.Error(),
		})
		return
	}

	if err := SaveToExel("sirius.xlsx", sirius.NewBolid().ZoneInfo()); err != nil {
		c.JSON(http.StatusBadRequest, &uploadResponse{
			Status: "error",
			Msg:    err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, &uploadResponse{
		Status: "ok",
	})
}

func SaveToExel(filename string, data []model.ZoneInfo) error {
	f := excelize.NewFile()
	defer func() {
		if err := f.Close(); err != nil {
			return
		}
	}()
	// Create a new sheet.
	f.SetCellValue("Sheet1", "A2", "№ зоны")
	f.SetCellValue("Sheet1", "B2", "Описание зоны")
	f.SetCellValue("Sheet1", "C2", "Адреса в зоне")
	i := 3
	for _, d := range data {
		f.SetCellValue("Sheet1", "A"+strconv.Itoa(i), d.ZoneNum)
		f.SetCellValue("Sheet1", "B"+strconv.Itoa(i), d.ZoneName)
		f.SetCellValue("Sheet1", "C"+strconv.Itoa(i), d.InputString())
		i++
	}
	// Save spreadsheet by the given path.
	if err := f.SaveAs(filename); err != nil {
		return err
	}
	return nil
}
