package main

import (
	"context"
	"fmt"
	"io/ioutil"
	"log"
	"os"

	"gopkg.in/urfave/cli.v1"

	"ur.gs/crockery/internal/imap"
	"ur.gs/crockery/internal/store"
)

func crockeryInit(c *cli.Context) error {
	db := c.GlobalString("db")
	domain := c.String("domain")
	certFile := c.String("cert")
	keyFile := c.String("key")
	postmasterPassword := c.String("postmaster-password")

	if db == "" {
		return fmt.Errorf("No crockery database file specified")
	}

	if domain == "" {
		return fmt.Errorf("A domain must be specified")
	}

	// FIXME: we can make cert+key optional at some point and have them be
	// generated on-demand via ACME during `crockery run` instead.
	if certFile == "" {
		return fmt.Errorf("A certificate file must be specified")
	}

	if keyFile == "" {
		return fmt.Errorf("A key file must be specified")
	}

	if postmasterPassword == "" {
		return fmt.Errorf("A password must be specified for the postmaster user")
	}

	if _, err := os.Stat(db); !os.IsNotExist(err) {
		return fmt.Errorf("File %q already exists, refusing to overwrite", db)
	}

	certPEM, err := ioutil.ReadFile(certFile)
	if err != nil {
		return fmt.Errorf("Failed to read certificate from %q: %v", certFile, err)
	}

	keyPEM, err := ioutil.ReadFile(keyFile)
	if err != nil {
		return fmt.Errorf("Failed to read key from %q: %v", keyFile, err)
	}

	if err := store.Init(db, domain, certPEM, keyPEM); err != nil {
		return fmt.Errorf("Couldn't initialize datase %q: %v", db, err)
	}

	datastore, err := store.New(context.Background(), db)
	if err != nil {
		return err
	}

	hash, err := store.HashPassword(postmasterPassword)
	if err != nil {
		return err
	}

	username := "postmaster@" + domain
	mailbox := store.Mailbox{
		Account: username,
		Name:    imap.InboxName,
	}

	if err := datastore.CreateMailbox(&mailbox); err != nil {
		return fmt.Errorf("Failed to create admin mailbox %s: %v", mailbox.Name, err)
	}

	postmaster := store.Account{
		Username:       username,
		Admin:          true,
		PasswordHash:   hash,
		DefaultMailbox: mailbox.ID, // Automatically filled in by the store
	}

	if err := datastore.CreateAccount(&postmaster); err != nil {
		return fmt.Errorf("Failed to create admin account %s: %v", postmaster.Username, err)
	}

	log.Printf("Created %q for domain %q. Next step:\n\t%s -db %s run", db, domain, os.Args[0], db)

	return nil
}
