package api

import (
	"errors"
	"time"
	"unicode"

	"code.google.com/p/go.text/unicode/norm"
	"secondbit.org/uuid"
)

var (
	CollectionNotFoundError  = errors.New("collection not found")
	DomainNotFoundError      = errors.New("domain not found")
	DomainAlreadyExistsError = errors.New("domain already attached to a collection")
	ItemNotFoundError        = errors.New("item not found")
	ItemAlreadyExistsError   = errors.New("item already exists")
	UserNotFoundError        = errors.New("user not found")
	UserAlreadyExistsError   = errors.New("user already exists")
	LoginNotFoundError       = errors.New("login not found")
	LoginAlreadyExistsError  = errors.New("login already exists")
)

type Datastore interface {
	CreateCollection(c Collection) error
	UpdateCollection(c Collection) error
	GetCollectionByDomain(domain string) (Collection, error)
	GetCollectionByID(id uuid.ID) (Collection, error)
	GetCollectionsByUser(id uuid.ID) ([]Collection, error)
	AddDomainToCollection(id uuid.ID, domain string) error
	RemoveDomainFromCollection(id uuid.ID, domain string) error
	GetDomainsByCollection(id uuid.ID) ([]Domain, error)
	DeleteCollection(c Collection) error

	GetItemsByCollectionDomain(domain string, num, offset int) ([]Item, error)
	GetItemsByCollectionID(id uuid.ID, num, offset int) ([]Item, error)
	AddItemToCollection(id uuid.ID, item Item) error
	GetItemByName(collectionID uuid.ID, name string) (Item, error)
	DeleteItem(item Item) error

	GetUserByID(id uuid.ID) (User, error)
	GetUserByLogin(loginType, value, passphrase string) (User, error)
	AddLoginToUser(login Login, user uuid.ID) error
	RemoveLoginFromUser(loginType, value string, user uuid.ID) error
	GetLoginsByUser(user uuid.ID) ([]Login, error)
	CreateUser(u User) error
	UpdateUser(u User) error
	DeleteUser(u User) error
}

func slugify(in string) string {
	buf := make([]rune, 0, len(in))
	needsDash := false
	for _, r := range norm.NFKD.String(in) {
		if unicode.IsSpace(r) || unicode.IsPunct(r) {
			if needsDash {
				buf = append(buf, '-')
				needsDash = false
			}
		} else {
			buf = append(buf, r)
			needsDash = true
		}
	}
	return string(buf)
}

type Collection struct {
	ID      uuid.ID
	Name    string
	Owner   uuid.ID
	Created time.Time
}

type Domain struct {
	Domain       string
	CollectionID uuid.ID
	Created      time.Time
}

type Item struct {
	Blob         string
	Bucket       string
	CollectionID uuid.ID
	Name         string
}

type User struct {
	ID         uuid.ID
	Name       string
	Passphrase string
	Email      string
	Created    time.Time
	LastSeen   time.Time
}

type Login struct {
	Type     string
	Value    string
	UserID   uuid.ID
	Created  time.Time
	LastUsed time.Time
}
