package geo

import (
	"errors"
	"fmt"
	"strings"
)

// ErrInvalidIP is returned when an IP cannot be parsed.
var ErrInvalidIP = errors.New("invalid ip address")

// ErrNotFound is returned when a backend cannot resolve the IP.
var ErrNotFound = errors.New("location not found")

type Backend string

const (
	BackendMMDB     Backend = "mmdb"
	BackendPostgres Backend = "postgres"
)

type Config struct {
	Backend     Backend
	MMDBPath    string
	DatabaseURL string
	LookupQuery string
}

type Resolver interface {
	Lookup(string) (Location, error)
	Close() error
}

type Location struct {
	IP        string
	Country   string
	Region    string
	City      string
	Address   string
	Latitude  float64
	Longitude float64
}

func NewResolver(cfg Config) (Resolver, error) {
	switch cfg.Backend {
	case "", BackendMMDB:
		return newMMDBResolver(cfg.MMDBPath)
	case BackendPostgres:
		return newPostgresResolver(cfg.DatabaseURL, cfg.LookupQuery)
	default:
		return nil, fmt.Errorf("unsupported backend %q", cfg.Backend)
	}
}

func buildAddress(parts ...string) string {
	addressParts := make([]string, 0, len(parts))
	for _, part := range parts {
		if part != "" {
			addressParts = append(addressParts, part)
		}
	}
	return strings.Join(addressParts, ", ")
}
