package main

import (
	"bytes"
	"encoding/csv"
	"encoding/xml"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"holiday-api/holiday"
	"net/http"
	"strconv"
	"time"
)

func getHolidays(service holiday.HolidayService) gin.HandlerFunc {
	return func(c *gin.Context) {
		paging := holiday.Paging{PageSize: 50}
		if err := c.ShouldBindQuery(&paging); err != nil {
			c.AbortWithError(http.StatusBadRequest, err)
			return
		}

		search := holiday.Search{}
		if err := c.ShouldBindQuery(&search); err != nil {
			c.AbortWithError(http.StatusBadRequest, err)
			return
		}

		holidays, err := service.Find(search, paging)
		if err != nil {
			render(c, http.StatusNotFound, ErrorResponse{Created: time.Now(), Message: "failed fetching holidays"}, nil)
		} else {
			render(c, http.StatusOK, mapHolidays(holidays), search.Type)
		}
	}
}

type DateResponse struct{ time.Time }

func (d DateResponse) MarshalJSON() ([]byte, error) {
	return []byte("\"" + d.String() + "\""), nil
}
func (d DateResponse) String() string {
	return fmt.Sprintf(`%04d-%02d-%02d`, d.Year(), d.Month(), d.Day())
}

type ErrorResponse struct {
	XMLName xml.Name  `json:"-" xml:"Error"`
	Created time.Time `json:"created" xml:"created"`
	Message string    `json:"message" xml:"message"`
	Code    int       `json:"-" xml:"-"`
}

type HolidayResponse struct {
	XMLName  xml.Name              `json:"-" xml:"Holidays"`
	Holidays []HolidayItemResponse `json:"holidays"`
}

func (h HolidayResponse) CSV() []byte {
	buffer := bytes.Buffer{}
	csvWriter := csv.NewWriter(&buffer)
	csvWriter.Write([]string{"id", "date", "name", "description", "isStateHoliday", "isReligiousHoliday"})

	for _, item := range h.Holidays {
		csvWriter.Write([]string{item.Id.String(), item.Date.String(), item.Name, item.Description, strconv.FormatBool(item.IsStateHoliday), strconv.FormatBool(item.IsReligiousHoliday)})
	}
	csvWriter.Flush()
	return buffer.Bytes()
}

type HolidayItemResponse struct {
	XMLName            xml.Name     `json:"-" xml:"Holiday"`
	Id                 uuid.UUID    `json:"id" xml:"id,attr"`
	Date               DateResponse `json:"date" xml:"date,attr"`
	Name               string       `json:"name" xml:"name"`
	Description        string       `json:"description" xml:"description,omitempty"`
	IsStateHoliday     bool         `json:"isStateHoliday" xml:"isState,attr"`
	IsReligiousHoliday bool         `json:"isReligiousHoliday" xml:"isReligious,attr"`
}

type HolidaySingleResponse struct {
	Id                 *uuid.UUID
	Country            string
	Date               DateResponse
	Name               string
	Description        string
	IsStateHoliday     bool
	IsReligiousHoliday bool
}

type HolidaySingleRequest struct {
	Id                 *uuid.UUID
	Country            string
	Date               DateResponse
	Name               string
	Description        string
	IsStateHoliday     bool
	IsReligiousHoliday bool
}

func mapHolidays(holidays []holiday.Holiday) HolidayResponse {
	var response = make([]HolidayItemResponse, 0, len(holidays))
	for _, h := range holidays {
		response = append(response, HolidayItemResponse{
			Id:                 h.Id,
			Date:               DateResponse{h.Date},
			Name:               h.Name,
			Description:        h.Description,
			IsStateHoliday:     h.IsStateHoliday,
			IsReligiousHoliday: h.IsReligiousHoliday,
		})
	}
	return HolidayResponse{
		Holidays: response,
	}
}
