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

// Package client provides a configured Lunatask API client.
package client

import (
	"errors"
	"fmt"
	"os"
	"runtime/debug"

	"git.secluded.site/go-lunatask"
	"github.com/zalando/go-keyring"
)

const (
	keyringService = "lune"
	keyringUser    = "api-key"
)

// ErrNoToken indicates no access token is available.
var ErrNoToken = errors.New("no access token found; set LUNE_ACCESS_TOKEN or run 'lune init' to configure")

// New creates a Lunatask client using the access token from LUNE_ACCESS_TOKEN
// environment variable or system keyring. Environment variable takes precedence.
func New() (*lunatask.Client, error) {
	token, err := GetToken()
	if err != nil {
		return nil, err
	}

	if token == "" {
		return nil, ErrNoToken
	}

	return lunatask.NewClient(token, lunatask.UserAgent("lune/"+version())), nil
}

// GetToken returns the access token from LUNE_ACCESS_TOKEN environment variable
// or keyring. Returns empty string and nil error if not found in either location;
// returns error for keyring access problems. Environment variable takes precedence.
func GetToken() (string, error) {
	// Env var takes precedence for explicit override
	if token := os.Getenv("LUNE_ACCESS_TOKEN"); token != "" {
		return token, nil
	}

	token, err := keyring.Get(keyringService, keyringUser)
	if err != nil {
		if errors.Is(err, keyring.ErrNotFound) {
			return "", nil
		}

		return "", fmt.Errorf("accessing system keyring: %w", err)
	}

	return token, nil
}

// SetToken stores the access token in the system keyring.
func SetToken(token string) error {
	if err := keyring.Set(keyringService, keyringUser, token); err != nil {
		return fmt.Errorf("keyring set: %w", err)
	}

	return nil
}

// DeleteToken removes the access token from the system keyring.
func DeleteToken() error {
	if err := keyring.Delete(keyringService, keyringUser); err != nil {
		return fmt.Errorf("keyring delete: %w", err)
	}

	return nil
}

// HasKeyringToken checks if an access token is stored in the keyring.
// Returns (true, nil) if found, (false, nil) if not found,
// or (false, error) if there was a keyring access problem.
func HasKeyringToken() (bool, error) {
	_, err := keyring.Get(keyringService, keyringUser)
	if err != nil {
		if errors.Is(err, keyring.ErrNotFound) {
			return false, nil
		}

		return false, fmt.Errorf("accessing system keyring: %w", err)
	}

	return true, nil
}

// version returns the module version from build info, or "dev" if unavailable.
func version() string {
	info, ok := debug.ReadBuildInfo()
	if !ok || info.Main.Version == "" || info.Main.Version == "(devel)" {
		return "dev"
	}

	return info.Main.Version
}
