//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 db

import (
	"errors"
	"github.com/pocketbase/dbx"
	"github.com/pocketbase/pocketbase"
	"github.com/pocketbase/pocketbase/core"
	"github.com/pocketbase/pocketbase/tools/types"
	"htwkalender/data-manager/model"
	"time"
)

var _ core.RecordProxy = (*Feed)(nil)

type Feed struct {
	core.BaseRecordProxy
}

type Feeds []*Feed

// Getter and Setter for the Feed struct

func (f *Feed) GetModules() string {
	return f.GetString("modules")
}

func (f *Feed) SetModules(modules string) {
	f.Set("modules", modules)
}

func (f *Feed) GetRetrieved() types.DateTime {
	return f.GetDateTime("retrieved")
}

func (f *Feed) SetRetrieved(retrieved types.DateTime) {
	f.Set("retrieved", retrieved)
}

func (f *Feed) GetDeleted() bool {
	return f.GetBool("deleted")
}

func (f *Feed) SetDeleted(deleted bool) {
	f.Set("deleted", deleted)
}

func (f *Feed) GetId() string {
	return f.GetString("id")
}

func (f *Feed) SetId(id string) {
	f.Set("id", id)
}

func (f *Feed) GetCreated() types.DateTime {
	return f.GetDateTime("created")
}

func (f *Feed) SetCreated(created time.Time) {
	f.Set("created", created)
}

func (f *Feed) GetUpdated() types.DateTime {
	return f.GetDateTime("updated")
}

func newFeed(record *core.Record) *Feed {
	return &Feed{
		BaseRecordProxy: core.BaseRecordProxy{Record: record},
	}
}

func NewFeed(collection *core.Collection, feed model.Feed) (*Feed, error) {
	// Create a new Feed instance
	if collection.Name != "feeds" {
		return nil, core.ErrInvalidFieldValue
	}

	record := core.NewRecord(collection)
	record.Set("id:autogenerate", "")

	dbFeed := newFeed(record)
	dbFeed.SetModules(feed.Modules)
	dbFeed.SetRetrieved(feed.Retrieved)
	dbFeed.SetDeleted(feed.Deleted)

	return dbFeed, nil
}

func (f *Feed) ToModel() model.Feed {
	return model.Feed{
		Modules:   f.GetModules(),
		Retrieved: f.GetRetrieved(),
		Created:   f.GetCreated(),
		Updated:   f.GetUpdated(),
		Deleted:   f.GetDeleted(),
		BaseModel: core.BaseModel{
			Id: f.GetId(),
		},
	}
}

func SaveFeed(feed model.Feed, collection *core.Collection, app *pocketbase.PocketBase) (model.Feed, error) {
	dbFeed, recordErr := NewFeed(collection, feed)
	if recordErr != nil {
		return model.Feed{}, recordErr
	}

	// Save the record to the database
	saveErr := app.Save(dbFeed)
	if saveErr != nil {
		return model.Feed{}, saveErr
	}

	return dbFeed.ToModel(), nil
}

func FindFeedByToken(app *pocketbase.PocketBase, token string) (*model.Feed, error) {

	record, err := app.FindRecordById("feeds", token)

	if err != nil {
		return nil, err
	}

	var feed model.Feed
	feed.Modules = record.GetString("modules")
	feed.Retrieved = record.GetDateTime("retrieved")
	feed.Deleted = record.GetBool("deleted")

	//update retrieved time if the is not marked as deleted
	if !record.GetBool("deleted") {
		record.Set("retrieved", time.Now())
		err = app.Save(record)
	}

	return &feed, err
}

func DeleteFeed(base *pocketbase.PocketBase, feedId string) error {

	sqlResult, err := base.DB().Delete("feeds", dbx.NewExp("id = {:id}", dbx.Params{"id": feedId})).Execute()
	var deletedRows int64
	if sqlResult != nil {
		deletedRows, _ = sqlResult.RowsAffected()
	}

	if err != nil {
		return err
	} else {
		if deletedRows == 0 {
			return errors.New("No feed with id " + feedId + " found")
		} else {
			return nil
		}
	}
}

func GetAllFeeds(base *pocketbase.PocketBase) ([]model.Feed, error) {
	var feeds []model.Feed
	err := base.DB().Select("*").From("feeds").All(&feeds)
	if err != nil {
		return nil, err
	}
	return feeds, nil
}

func MarkForDelete(base *pocketbase.PocketBase, token string) error {
	// get record from db
	feed := model.Feed{}
	err := base.DB().Select("*").From("feeds").Where(dbx.NewExp("id = {:id}", dbx.Params{"id": token})).One(&feed)
	if err != nil {
		return err
	}
	// set delete flag
	feed.Deleted = true
	feed.Modules = "[\n  {\n    \"uuid\": \"\",\n    \"name\": \"Deleted\",\n    \"course\": \"\",\n    \"userDefinedName\": \"Deleted\",\n    \"reminder\": false\n  }\n]"

	// save record
	err = base.Save(&feed)
	if err != nil {
		return err
	}
	return nil
}
