//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
//Copyright (C) 2024 HTWKalender support@htwkalender.de

//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU Affero General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU Affero General Public License for more details.

//You should have received a copy of the GNU Affero General Public License
//along with this program.  If not, see <https://www.gnu.org/licenses/>.

package ical

import (
	"fmt"
	"htwkalender/ical/model"
	"htwkalender/ical/service/connector"
	htwkalenderGrpc "htwkalender/ical/service/connector/grpc"
	"htwkalender/ical/service/functions"
	"log/slog"
	"time"
)

const expirationTime = 5 * time.Minute

var ErrFeedDeleted = fmt.Errorf("feed deleted")

func Feed(app model.AppType, token string, userAgent string) (string, string, error) {

	var events model.Events
	modules := map[string]model.FeedCollection{}

	if token == "test" {
		// write down list of modules
		modules = generateTestModules()

		// generate test feed with events from the last 7 days to the next 7 days
		events = generateTestEvents(modules)

	} else {
		// get feed by token
		feed, err := htwkalenderGrpc.GetFeed(token, app.GrpcClient)
		if err != nil {
			return "", "", err
		}

		if feed.Deleted {
			return "", "", ErrFeedDeleted
		}

		// Get all events for modules
		events, err = htwkalenderGrpc.GetEventsByModules(feed.Modules, app.GrpcClient)
		if err != nil {
			return "", "", err
		}

		// Sort events by start date
		events.Sort()

		for _, module := range feed.Modules {
			modules[module.UUID] = model.FeedCollection(module)
		}
	}

	// Generate one Hash for E-TAG from all events and modules
	etag := functions.HashString(events.String() + fmt.Sprint(modules))

	cal := GenerateIcalFeed(events, modules, userAgent)
	icalFeed := &model.FeedModel{Content: cal.Serialize(), ExpiresAt: model.JSONTime(time.Now().Add(expirationTime))}

	return icalFeed.Content, etag, nil
}

func FeedRecord(app model.AppType, token string) (model.FeedRecord, error) {

	feedRecord, err := connector.GetFeedByToken(app.DataManagerURL, token)
	if err != nil {
		return model.FeedRecord{}, err
	}

	return feedRecord, nil

}

func DeleteFeedRecord(app model.AppType, token string) error {
	err := connector.DeleteFeedRecord(app, token)
	if err != nil {
		return err
	}
	return nil
}

func CreateFeed(app model.AppType, modules []model.FeedCollection) (string, error) {

	// Save feed
	token, err := connector.SaveFeedRecord(app, modules)
	if err != nil {
		slog.Error("Failed to save feed", "error", err)
		return "", err
	}

	return token, nil
}

func FeedRoom(app model.AppType, room string, userAgent string) (string, string, error) {

	// Get all events for room
	events, err := htwkalenderGrpc.GetEventsByRoom(room, app.GrpcClient)
	if err != nil {
		return "", "", err
	}

	// Sort events by start date
	events.Sort()

	// Generate one Hash for E-TAG from all events
	etag := functions.HashString(events.String())

	cal := GenerateIcalFeed(events, map[string]model.FeedCollection{}, userAgent)
	icalFeed := &model.FeedModel{Content: cal.Serialize(), ExpiresAt: model.JSONTime(time.Now().Add(expirationTime))}

	return icalFeed.Content, etag, nil
}
