package main

import (
	"fmt"
	"os"
	"path"

	uuid "github.com/satori/go.uuid"
)

type CmdShare struct {
	CmdList     CmdShareList     `cmd:"" name:"list" help:"List all shares."`
	CmdCreate   CmdShareCreate   `cmd:"" name:"create" help:"Create a new share."`
	CmdDelete   CmdShareDelete   `cmd:"" name:"delete" help:"Delete a share."`
	CmdAddUser  CmdShareAddUser  `cmd:"" name:"add-user" help:"Add user to share."`
	CmdAddLogin CmdShareAddLogin `cmd:"" name:"add-login" help:"Add login to share."`
}

type CmdShareList struct{}

func (cmd *CmdShareList) Run(app *app) error {
	shares, err := app.shareStore.GetShares()
	if err != nil {
		return err
	}

	for _, share := range shares {
		fmt.Printf("* %s (%s)\n", share.UUID.String(), share.Name)
	}

	return nil
}

type CmdShareCreate struct {
	Name string `name:"name" help:"Name of the share." required:""`
}

func (cmd *CmdShareCreate) Run(app *app) error {
	share, err := app.shareStore.CreateShare()
	if err != nil {
		return err
	}
	share.Name = cmd.Name
	if err := app.shareStore.UpdateShareAttributes(share); err != nil {
		// Best effort cleanup.
		_ = app.shareStore.RemoveShare(share.UUID)

		return fmt.Errorf("cannot set share attributes: %v", err)
	}

	if err := os.MkdirAll(path.Join(app.DataDirectory, share.UUID.String()), 0750); err != nil {
		// Best effort cleanup.
		_ = app.shareStore.RemoveShare(share.UUID)

		return fmt.Errorf("cannot create data dir: %v", err)
	}

	fmt.Printf("Share created: %s\n", share.UUID.String())
	return nil
}

type ShareIdentifier struct {
	UUID uuid.UUID `arg:"" name:"id" help:"ID of the share to be deleted." required:""`
}

type CmdShareDelete struct {
	ShareIdentifier
}

func (cmd *CmdShareDelete) Run(app *app) error {
	if err := os.RemoveAll(path.Join(app.DataDirectory, cmd.UUID.String())); err != nil {
		return fmt.Errorf("cannot remove data directory: %v", err)
	}

	if err := app.shareStore.RemoveShare(cmd.UUID); err != nil {
		return fmt.Errorf("cannot remove share: %v", err)
	}

	return nil
}

type CmdShareAddUser struct {
	ShareIdentifier
	Username string    `arg:"" name:"username" help:"Username of the user to add."`
	Role     ShareRole `name:"role" help:"Role of the user (reader/writer/admin)" default:"writer"`
}

func (cmd *CmdShareAddUser) Run(app *app) error {
	if _, err := app.userStore.GetUser(cmd.Username); err != nil {
		return err
	}

	share := Share{UUID: cmd.UUID}
	return app.shareStore.AddUserToShare(share, cmd.Username, cmd.Role)
}

type CmdShareAddLogin struct {
	ShareIdentifier
	Username  string `arg:"" name:"username" help:"Username of the user to add the login for."`
	LoginName string `arg:"" name:"loginname" help:"Name f the login. Must be unique."`
	ReadOnly  bool   `name:"readonly" help:"If set, the login can only read."`
	PasswordParam
}

func (cmd *CmdShareAddLogin) Run(app *app) error {
	if _, err := app.userStore.GetUser(cmd.Username); err != nil {
		return err
	}

	password, err := cmd.acquirePassword()
	if err != nil {
		return fmt.Errorf("cannot acquire password for login: %w", err)
	}

	share := Share{UUID: cmd.UUID}
	login := Login{
		LoginName: cmd.LoginName,
		Password:  password,
		ReadOnly:  cmd.ReadOnly,
	}

	return app.shareStore.AddLogin(share, cmd.Username, login)
}
