// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

// Package shared provides common interfaces, types, and helpers for MCP tools.
package shared

import (
	"errors"
	"fmt"
	"time"
)

// ErrTimezoneNotConfigured is returned when the timezone config value is empty.
var ErrTimezoneNotConfigured = errors.New(
	"timezone is not configured; please set the 'timezone' value in your " +
		"config file (e.g. 'UTC' or 'America/New_York')",
)

// AreaProvider defines the interface for accessing area data.
type AreaProvider interface {
	GetName() string
	GetID() string
	GetKey() string
	GetGoals() []GoalProvider
}

// GoalProvider defines the interface for accessing goal data.
//
//nolint:iface // semantically distinct from HabitProvider
type GoalProvider interface {
	GetName() string
	GetID() string
	GetKey() string
}

// HabitProvider defines the interface for accessing habit data.
//
//nolint:iface // semantically distinct from GoalProvider
type HabitProvider interface {
	GetName() string
	GetID() string
	GetKey() string
}

// Config holds the necessary configuration for tool handlers.
type Config struct {
	AccessToken string
	Timezone    string
	Areas       []AreaProvider
	Habits      []HabitProvider
}

// LoadLocation loads a timezone location string, returning a *time.Location or error.
func LoadLocation(timezone string) (*time.Location, error) {
	if timezone == "" {
		return nil, ErrTimezoneNotConfigured
	}

	loc, err := time.LoadLocation(timezone)
	if err != nil {
		return nil, fmt.Errorf("could not load timezone '%s': %w", timezone, err)
	}

	return loc, nil
}

// FindArea finds an area by ID or key from the list of providers. Returns nil if not found.
func FindArea(areas []AreaProvider, idOrKey string) AreaProvider {
	for _, ap := range areas {
		if ap.GetID() == idOrKey || ap.GetKey() == idOrKey {
			return ap
		}
	}

	return nil
}

// FindGoalInArea checks if a goal exists within an area by ID or key.
// Returns true if found.
func FindGoalInArea(area AreaProvider, idOrKey string) bool {
	for _, goal := range area.GetGoals() {
		if goal.GetID() == idOrKey || goal.GetKey() == idOrKey {
			return true
		}
	}

	return false
}

// GetGoalInArea finds a goal within an area by ID or key.
// Returns nil if not found.
func GetGoalInArea(area AreaProvider, idOrKey string) GoalProvider {
	for _, goal := range area.GetGoals() {
		if goal.GetID() == idOrKey || goal.GetKey() == idOrKey {
			return goal
		}
	}

	return nil
}

// FindHabit finds a habit by ID or key from the list of providers. Returns nil if not found.
func FindHabit(habits []HabitProvider, idOrKey string) HabitProvider {
	for _, hp := range habits {
		if hp.GetID() == idOrKey || hp.GetKey() == idOrKey {
			return hp
		}
	}

	return nil
}
