package storage

import (
	"time"

	"gorm.io/gorm"
)

type RemoteServer struct {
	ID        string    `gorm:"primarykey"` // ID is also server url
	CreatedAt time.Time // When this entry was created
	UpdatedAt time.Time // When this entry was last updated
	// When this entry was deleted (for soft deletions)
	// Soft delete means that this entry still exists in the db, but gorm won't include it anymore unless specifically told to
	// If not null, this entry is marked as deleted
	DeletedAt  gorm.DeletedAt   `gorm:"index"`
	ServerType RemoteServerType // What software the server is running. Useful for formatting
	Name       string           // What the server wants to be known as (usually same as url)
	Icon       string           // ID of a media file
	IsSelf     bool             // Whether this server is yours truly
}

func (s *Storage) FindRemoteServer(url string) (*RemoteServer, error) {
	server := RemoteServer{
		ID: url,
	}
	err := s.db.First(&server).Error
	switch err {
	case nil:
		return &server, nil
	case gorm.ErrRecordNotFound:
		return nil, ErrEntryNotFound
	default:
		return nil, err
	}
}

// Find a remote server with a given display name
func (s *Storage) FindRemoteServerByDisplayName(displayName string) (*RemoteServer, error) {
	server := RemoteServer{}
	err := s.db.Where("name = ?", displayName).First(&server).Error
	switch err {
	case nil:
		return &server, nil
	case gorm.ErrRecordNotFound:
		return nil, ErrEntryNotFound
	default:
		return nil, err
	}
}

// Create a new remote server
func (s *Storage) NewRemoteServer(
	url, displayName, icon string,
	serverType RemoteServerType,
) (*RemoteServer, error) {
	_, err := s.FindRemoteServer(url)
	switch err {
	case nil:
		return nil, ErrEntryAlreadyExists
	case ErrEntryNotFound: // Empty case, not found is what we want
	default:
		return nil, err
	}
	server := RemoteServer{
		ID:         url,
		Name:       displayName,
		Icon:       icon,
		ServerType: serverType,
	}
	err = s.db.Create(&server).Error
	if err != nil {
		return nil, err
	}
	return &server, nil
}

// Update a remote server with the given url
// If displayName is set, update that
// If icon is set, update that
// Returns the updated version
func (s *Storage) UpdateRemoteServer(url string, displayName, icon *string) (*RemoteServer, error) {
	if displayName == nil && icon == nil {
		return nil, ErrNothingToChange
	}
	server, err := s.FindRemoteServer(url)
	if err != nil {
		return nil, err
	}
	if displayName != nil {
		server.Name = *displayName
	}
	if icon != nil {
		server.Icon = *icon
	}
	err = s.db.Save(server).Error
	if err != nil {
		return nil, err
	}
	return server, nil
}
