package graph

// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
// Code generated by github.com/99designs/gqlgen version v0.17.24

import (
	"context"
	"errors"
	"strconv"
	"time"

	"github.com/99designs/gqlgen/graphql"
	"github.com/Unkn0wnCat/calapi/graph/model"
	"github.com/Unkn0wnCat/calapi/internal/auth"
	"github.com/Unkn0wnCat/calapi/internal/database"
	"github.com/Unkn0wnCat/calapi/internal/db_model"
	"github.com/Unkn0wnCat/calapi/internal/logger"
	"github.com/go-chi/chi/middleware"
	"github.com/objectbox/objectbox-go/objectbox"
	"go.uber.org/zap"
)

// Events is the resolver for the events field.
func (r *calendarResolver) Events(ctx context.Context, obj *model.Calendar, after *time.Time, before *time.Time) ([]*model.Event, error) {
	if auth.ChallengeQuery(ctx) != nil {
		return nil, errors.New("unauthorized")
	}

	if after == nil {
		now := time.Now()
		after = &now
	}
	if before == nil {
		oneYearLater := time.Now().Add(time.Hour * 24 * 365)
		before = &oneYearLater
	}

	eventBox := db_model.BoxForEvent(database.ObjectBox)

	filters := []objectbox.Condition{db_model.Event_.Start.Between(after.UnixMilli(), before.UnixMilli()), db_model.Event_.Start.OrderAsc()}

	filters = append(filters, db_model.Event_.Calendar.In(obj.DbID))

	query := eventBox.Query(filters...)
	results, err := query.Find()
	if err != nil {
		return nil, err
	}

	events := make([]*model.Event, len(results))

	for i, result := range results {
		event := model.FromEvent(*result)
		events[i] = &event
	}

	return events, nil
}

// Calendar is the resolver for the calendar field.
func (r *eventResolver) Calendar(ctx context.Context, obj *model.Event) (*model.Calendar, error) {
	if auth.ChallengeQuery(ctx) != nil {
		return nil, errors.New("unauthorized")
	}

	modelCalendar := model.FromCalendar(*obj.DbCalendar)

	return &modelCalendar, nil
}

// CreateEvent is the resolver for the createEvent field.
func (r *mutationResolver) CreateEvent(ctx context.Context, input model.NewEvent) (*model.Event, error) {
	if auth.ChallengeMutation(ctx) != nil {
		return nil, errors.New("unauthorized")
	}

	actualId, err := strconv.ParseUint(input.Calendar, 16, 64)
	if err != nil {
		return nil, err
	}

	calendarBox := db_model.BoxForCalendar(database.ObjectBox)
	calendar, err := calendarBox.Get(actualId)
	if err != nil {
		return nil, err
	}
	if calendar == nil {
		return nil, errors.New("calendar not found")
	}

	event := db_model.Event{
		Title:        input.Title,
		Description:  input.Description,
		Calendar:     calendar,
		LocationLat:  0,
		LocationLon:  0,
		LocationName: "",
		LocationAddr: "",
		Start:        input.Start,
		End:          input.End,
		DateCreated:  time.Now(),
	}

	if input.Location != nil {
		if input.Location.Lat != nil && input.Location.Lon != nil {
			event.LocationLat = *input.Location.Lat
			event.LocationLon = *input.Location.Lon
		}
		if input.Location.Name != nil {
			event.LocationName = *input.Location.Name
		}
		if input.Location.Address != nil {
			event.LocationAddr = *input.Location.Address
		}
	}

	eventBox := db_model.BoxForEvent(database.ObjectBox)
	_, err = eventBox.Put(&event)
	if err != nil {
		return nil, err
	}

	modelEvent := model.FromEvent(event)

	logger.Logger.Info("event created",
		zap.String("requestId", middleware.GetReqID(ctx)),
		zap.String("gqlPath", graphql.GetPath(ctx).String()),
		zap.Uint64("newID", event.Id),
	)

	return &modelEvent, nil
}

// EditEvent is the resolver for the editEvent field.
func (r *mutationResolver) EditEvent(ctx context.Context, input model.EditEvent) (*model.Event, error) {
	if auth.ChallengeMutation(ctx) != nil {
		return nil, errors.New("unauthorized")
	}

	actualId, err := strconv.ParseUint(input.ID, 16, 64)
	if err != nil {
		return nil, err
	}

	eventBox := db_model.BoxForEvent(database.ObjectBox)
	event, err := eventBox.Get(actualId)
	if err != nil {
		return nil, err
	}
	if event == nil {
		return nil, errors.New("event not found")
	}

	if input.Location != nil {
		if input.Location.Lat != nil && input.Location.Lon != nil {
			event.LocationLat = *input.Location.Lat
			event.LocationLon = *input.Location.Lon
		}
		if input.Location.Name != nil {
			event.LocationName = *input.Location.Name
		}
		if input.Location.Address != nil {
			event.LocationAddr = *input.Location.Address
		}
	}

	if input.Start != nil {
		event.Start = *input.Start
	}

	if input.End != nil {
		event.End = *input.End
	}

	if input.Title != nil {
		event.Title = *input.Title
	}

	if input.Description != nil {
		event.Description = *input.Description
	}

	if input.Calendar != nil {
		calendarId, err := strconv.ParseUint(input.ID, 16, 64)
		if err != nil {
			return nil, err
		}

		calendarBox := db_model.BoxForCalendar(database.ObjectBox)
		calendar, err := calendarBox.Get(calendarId)
		if err != nil {
			return nil, err
		}
		if calendar == nil {
			return nil, errors.New("calendar not found")
		}
		event.Calendar = calendar
	}

	err = eventBox.Update(event)
	if err != nil {
		return nil, err
	}

	modelEvent := model.FromEvent(*event)

	logger.Logger.Info("event edited",
		zap.String("requestId", middleware.GetReqID(ctx)),
		zap.String("gqlPath", graphql.GetPath(ctx).String()),
		zap.Uint64("ID", event.Id),
	)

	return &modelEvent, nil
}

// DeleteEvent is the resolver for the deleteEvent field.
func (r *mutationResolver) DeleteEvent(ctx context.Context, input string) (bool, error) {
	if auth.ChallengeMutation(ctx) != nil {
		return false, errors.New("unauthorized")
	}

	actualId, err := strconv.ParseUint(input, 16, 64)
	if err != nil {
		return false, err
	}

	eventBox := db_model.BoxForEvent(database.ObjectBox)
	err = eventBox.RemoveId(actualId)
	if err != nil {
		return false, err
	}

	logger.Logger.Info("event deleted",
		zap.String("requestId", middleware.GetReqID(ctx)),
		zap.String("gqlPath", graphql.GetPath(ctx).String()),
		zap.Uint64("oldID", actualId),
	)

	return true, nil
}

// CreateCalendar is the resolver for the createCalendar field.
func (r *mutationResolver) CreateCalendar(ctx context.Context, input model.NewCalendar) (*model.Calendar, error) {
	if auth.ChallengeMutation(ctx) != nil {
		return nil, errors.New("unauthorized")
	}

	calendar := db_model.Calendar{
		Name:        input.Name,
		Description: input.Description,
		DateCreated: time.Now(),
	}

	calendarBox := db_model.BoxForCalendar(database.ObjectBox)
	_, err := calendarBox.Put(&calendar)
	if err != nil {
		return nil, err
	}

	modelCalendar := model.FromCalendar(calendar)

	logger.Logger.Info("calendar created",
		zap.String("requestId", middleware.GetReqID(ctx)),
		zap.String("gqlPath", graphql.GetPath(ctx).String()),
		zap.Uint64("newID", calendar.Id),
	)

	return &modelCalendar, nil
}

// EditCalendar is the resolver for the editCalendar field.
func (r *mutationResolver) EditCalendar(ctx context.Context, input model.EditCalendar) (*model.Calendar, error) {
	if auth.ChallengeMutation(ctx) != nil {
		return nil, errors.New("unauthorized")
	}

	actualId, err := strconv.ParseUint(input.ID, 16, 64)
	if err != nil {
		return nil, err
	}

	calendarBox := db_model.BoxForCalendar(database.ObjectBox)
	calendar, err := calendarBox.Get(actualId)
	if err != nil {
		return nil, err
	}
	if calendar == nil {
		return nil, errors.New("calendar not found")
	}

	if input.Name != nil {
		calendar.Name = *input.Name
	}

	if input.Description != nil {
		calendar.Description = *input.Description
	}

	err = calendarBox.Update(calendar)
	if err != nil {
		return nil, err
	}

	modelCalendar := model.FromCalendar(*calendar)

	logger.Logger.Info("calendar edited",
		zap.String("requestId", middleware.GetReqID(ctx)),
		zap.String("gqlPath", graphql.GetPath(ctx).String()),
		zap.Uint64("ID", calendar.Id),
	)

	return &modelCalendar, nil
}

// DeleteCalendar is the resolver for the deleteCalendar field.
func (r *mutationResolver) DeleteCalendar(ctx context.Context, input string) (bool, error) {
	if auth.ChallengeMutation(ctx) != nil {
		return false, errors.New("unauthorized")
	}

	actualId, err := strconv.ParseUint(input, 16, 64)
	if err != nil {
		return false, err
	}

	calendarBox := db_model.BoxForCalendar(database.ObjectBox)
	err = calendarBox.RemoveId(actualId)
	if err != nil {
		return false, err
	}

	logger.Logger.Info("calendar deleted",
		zap.String("requestId", middleware.GetReqID(ctx)),
		zap.String("gqlPath", graphql.GetPath(ctx).String()),
		zap.Uint64("newID", actualId),
	)

	return true, nil
}

// Login is the resolver for the login field.
func (r *mutationResolver) Login(ctx context.Context, input model.Login) (string, error) {
	user, err := auth.Authenticate(ctx, input.Username, input.Password)
	if err != nil || user == nil {
		return "", errors.New("invalid credentials")
	}

	token, err := auth.MakeJWT(user)
	if err != nil {
		return "", errors.New("failed to create token")
	}

	return token, nil
}

// Events is the resolver for the events field.
func (r *queryResolver) Events(ctx context.Context, after *time.Time, before *time.Time, calendar *string) ([]*model.Event, error) {
	if auth.ChallengeQuery(ctx) != nil {
		return nil, errors.New("unauthorized")
	}

	if after == nil {
		now := time.Now()
		after = &now
	}
	if before == nil {
		oneYearLater := time.Now().Add(time.Hour * 24 * 365)
		before = &oneYearLater
	}

	eventBox := db_model.BoxForEvent(database.ObjectBox)

	filters := []objectbox.Condition{db_model.Event_.Start.Between(after.UnixMilli(), before.UnixMilli()), db_model.Event_.Start.OrderAsc()}

	if calendar != nil {
		calendarId, err := strconv.ParseUint(*calendar, 16, 64)
		if err != nil {
			return nil, err
		}

		filters = append(filters, db_model.Event_.Calendar.In(calendarId))
	}

	query := eventBox.Query(filters...)
	results, err := query.Find()
	if err != nil {
		return nil, err
	}

	events := make([]*model.Event, len(results))

	for i, result := range results {
		event := model.FromEvent(*result)
		events[i] = &event
	}

	return events, nil
}

// Calendars is the resolver for the calendars field.
func (r *queryResolver) Calendars(ctx context.Context) ([]*model.Calendar, error) {
	if auth.ChallengeQuery(ctx) != nil {
		return nil, errors.New("unauthorized")
	}

	calendarBox := db_model.BoxForCalendar(database.ObjectBox)
	results, err := calendarBox.GetAll()
	if err != nil {
		return nil, err
	}

	calendars := make([]*model.Calendar, len(results))

	for i, result := range results {
		calendar := model.FromCalendar(*result)
		calendars[i] = &calendar
	}

	return calendars, nil
}

// Calendar is the resolver for the calendar field.
func (r *queryResolver) Calendar(ctx context.Context, id string) (*model.Calendar, error) {
	if auth.ChallengeQuery(ctx) != nil {
		return nil, errors.New("unauthorized")
	}

	actualId, err := strconv.ParseUint(id, 16, 64)
	if err != nil {
		return nil, err
	}

	calendarBox := db_model.BoxForCalendar(database.ObjectBox)
	calendar, err := calendarBox.Get(actualId)
	if err != nil {
		return nil, err
	}

	if calendar == nil {
		return nil, errors.New("not found")
	}

	modelCalendar := model.FromCalendar(*calendar)
	return &modelCalendar, nil
}

// Event is the resolver for the event field.
func (r *queryResolver) Event(ctx context.Context, id string) (*model.Event, error) {
	if auth.ChallengeQuery(ctx) != nil {
		return nil, errors.New("unauthorized")
	}

	actualId, err := strconv.ParseUint(id, 16, 64)
	if err != nil {
		return nil, err
	}

	eventBox := db_model.BoxForEvent(database.ObjectBox)
	event, err := eventBox.Get(actualId)
	if err != nil {
		return nil, err
	}

	if event == nil {
		return nil, errors.New("not found")
	}

	modelEvent := model.FromEvent(*event)
	return &modelEvent, nil
}

// Calendar returns CalendarResolver implementation.
func (r *Resolver) Calendar() CalendarResolver { return &calendarResolver{r} }

// Event returns EventResolver implementation.
func (r *Resolver) Event() EventResolver { return &eventResolver{r} }

// Mutation returns MutationResolver implementation.
func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} }

// Query returns QueryResolver implementation.
func (r *Resolver) Query() QueryResolver { return &queryResolver{r} }

type calendarResolver struct{ *Resolver }
type eventResolver struct{ *Resolver }
type mutationResolver struct{ *Resolver }
type queryResolver struct{ *Resolver }