//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 (
	ics "github.com/arran4/golang-ical"
	"htwkalender/ical/model"
	"htwkalender/ical/service/functions"
	"log/slog"
	"net/url"
	"strings"
	_ "time/tzdata"
)

const (
	Thunderbird    = "Thunderbird"
	GoogleCalendar = "Google-Calendar-Importer"
)

// Adds a user-agent specific description and ALTREP to the calendar event.
func addUserAgentSpecificDescription(vEvent *ics.VEvent, event model.Event, userAgent string) {
	description, altrep := generateDescription(event, userAgent)

	if userAgentType := identifyUserAgent(userAgent); userAgentType == Thunderbird && altrep != "" {
		vEvent.AddProperty(ics.ComponentPropertyDescription, description, ics.WithAlternativeRepresentation(buildDataURL(altrep)))
	} else {
		vEvent.AddProperty(ics.ComponentPropertyDescription, description)
	}
}

// Generates a description and ALTREP (alternative representation) based on the user agent.
func generateDescription(event model.Event, userAgent string) (string, string) {
	plainDescription := buildPlainTextDescription(event)

	switch identifyUserAgent(userAgent) {
	case Thunderbird:
		htmlDescription := generateHTMLDescriptionForThunderbird(event)
		altrep := "text/html," + url.PathEscape(htmlDescription)
		return plainDescription, altrep
	case GoogleCalendar:
		plainDescription += generateRoomLinksForGoogleCalendar(event.Rooms)
	}
	return plainDescription, ""
}

// Builds a plain text description of the event details.
func buildPlainTextDescription(event model.Event) string {
	var description strings.Builder

	if !functions.OnlyWhitespace(event.Prof) {
		description.WriteString("Profs: " + event.Prof + "\n")
	}
	if !functions.OnlyWhitespace(event.Course) {
		description.WriteString("Gruppen: " + event.Course + "\n")
	}
	if !functions.OnlyWhitespace(event.EventType) {
		description.WriteString("Typ: " + event.EventType + event.Compulsory + "\n")
	}
	if !functions.OnlyWhitespace(event.Notes) {
		description.WriteString("Notizen: " + event.Notes + "\n")
	}

	return description.String()
}

// Generates an HTML description for Thunderbird users.
func generateHTMLDescriptionForThunderbird(event model.Event) string {
	var htmlDescription strings.Builder

	if !functions.OnlyWhitespace(event.Prof) {
		htmlDescription.WriteString("Profs: " + event.Prof + "<br>")
	}
	if !functions.OnlyWhitespace(event.Course) {
		htmlDescription.WriteString("Gruppen: " + event.Course + "<br>")
	}
	if !functions.OnlyWhitespace(event.EventType) {
		htmlDescription.WriteString("Typ: " + event.EventType + event.Compulsory + "<br>")
	}

	if !functions.OnlyWhitespace(event.Rooms) {
		htmlDescription.WriteString("Orte: ")
		for _, room := range functions.SeperateRoomString(event.Rooms) {
			roomLink := functions.MapRoom(room, true)
			_, err := htmlDescription.WriteString("<a href=\"https://map.htwk-leipzig.de/room/" + roomLink + "\">" + room + "</a> ")
			if err != nil {
				slog.Error("Error while writing to HTML description", "error", err)
				return ""
			}
		}
	}

	return htmlDescription.String()
}

// Generates room links formatted for Google Calendar.
func generateRoomLinksForGoogleCalendar(rooms string) string {
	var description strings.Builder
	roomList := functions.SeperateRoomString(rooms)

	if !functions.OnlyWhitespace(rooms) {
		description.WriteString("Orte: ")
		for _, room := range roomList {
			roomLink := functions.MapRoom(room, true)
			description.WriteString("<a href=\"https://map.htwk-leipzig.de/room/" + roomLink + "\"> " + room + " </a> ")
		}
	}

	return description.String()
}

// Identifies the user agent type (e.g., Thunderbird or Google Calendar).
func identifyUserAgent(userAgent string) string {
	if strings.Contains(userAgent, Thunderbird) {
		return Thunderbird
	}
	if strings.Contains(userAgent, GoogleCalendar) {
		return GoogleCalendar
	}
	return ""
}

// Constructs a data URL for the ALTREP representation.
func buildDataURL(data string) *url.URL {
	return &url.URL{Scheme: "data", Opaque: data}
}
