/*
 * Copyright © 2018-2021 Musing Studio LLC.
 *
 * This file is part of WriteFreely.
 *
 * WriteFreely is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, included
 * in the LICENSE file in this source code package.
 */

package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/gorilla/mux"
	"github.com/urfave/cli/v2"
	"github.com/writeas/web-core/log"
	"github.com/writefreely/writefreely"
)

func main() {
	cli.VersionPrinter = func(c *cli.Context) {
		fmt.Printf("%s\n", c.App.Version)
	}
	app := &cli.App{
		Name:    "WriteFreely",
		Usage:   "A beautifully pared-down blogging platform",
		Version: writefreely.FormatVersion(),
		Action:  legacyActions, // legacy due to use of flags for switching actions
		Flags: []cli.Flag{
			&cli.BoolFlag{
				Name:   "create-config",
				Value:  false,
				Usage:  "Generate a basic configuration",
				Hidden: true,
			},
			&cli.BoolFlag{
				Name:   "config",
				Value:  false,
				Usage:  "Interactive configuration process",
				Hidden: true,
			},
			&cli.StringFlag{
				Name:  "sections",
				Value: "server db app",
				Usage: "Which sections of the configuration to go through (requires --config)\n" +
					"valid values are any combination of 'server', 'db' and 'app' \n" +
					"example: writefreely --config --sections \"db app\"",
				Hidden: true,
			},
			&cli.BoolFlag{
				Name:   "gen-keys",
				Value:  false,
				Usage:  "Generate encryption and authentication keys",
				Hidden: true,
			},
			&cli.BoolFlag{
				Name:   "init-db",
				Value:  false,
				Usage:  "Initialize app database",
				Hidden: true,
			},
			&cli.BoolFlag{
				Name:   "migrate",
				Value:  false,
				Usage:  "Migrate the database",
				Hidden: true,
			},
			&cli.StringFlag{
				Name:   "create-admin",
				Usage:  "Create an admin with the given username:password",
				Hidden: true,
			},
			&cli.StringFlag{
				Name:   "create-user",
				Usage:  "Create a regular user with the given username:password",
				Hidden: true,
			},
			&cli.StringFlag{
				Name:   "delete-user",
				Usage:  "Delete a user with the given username",
				Hidden: true,
			},
			&cli.StringFlag{
				Name:   "reset-pass",
				Usage:  "Reset the given user's password",
				Hidden: true,
			},
		}, // legacy flags (set to hidden to eventually switch to bash-complete compatible format)
	}

	defaultFlags := []cli.Flag{
		&cli.StringFlag{
			Name:  "c",
			Value: "config.ini",
			Usage: "Load configuration from `FILE`",
		},
		&cli.BoolFlag{
			Name:  "debug",
			Value: false,
			Usage: "Enables debug logging",
		},
	}

	app.Flags = append(app.Flags, defaultFlags...)

	app.Commands = []*cli.Command{
		&cmdUser,
		&cmdDB,
		&cmdConfig,
		&cmdKeys,
		&cmdServe,
	}

	err := app.Run(os.Args)
	if err != nil {
		log.Error(err.Error())
		os.Exit(1)
	}
}

func legacyActions(c *cli.Context) error {
	app := writefreely.NewApp(c.String("c"))

	switch true {
	case c.IsSet("create-config"):
		return writefreely.CreateConfig(app)
	case c.IsSet("config"):
		writefreely.DoConfig(app, c.String("sections"))
		return nil
	case c.IsSet("gen-keys"):
		return writefreely.GenerateKeyFiles(app)
	case c.IsSet("init-db"):
		return writefreely.CreateSchema(app)
	case c.IsSet("migrate"):
		return writefreely.Migrate(app)
	case c.IsSet("create-admin"):
		username, password, err := parseCredentials(c.String("create-admin"))
		if err != nil {
			return err
		}
		return writefreely.CreateUser(app, username, password, true)
	case c.IsSet("create-user"):
		username, password, err := parseCredentials(c.String("create-user"))
		if err != nil {
			return err
		}
		return writefreely.CreateUser(app, username, password, false)
	case c.IsSet("delete-user"):
		return writefreely.DoDeleteAccount(app, c.String("delete-user"))
	case c.IsSet("reset-pass"):
		return writefreely.ResetPassword(app, c.String("reset-pass"))
	}

	// Initialize the application
	var err error
	log.Info("Starting %s...", writefreely.FormatVersion())
	app, err = writefreely.Initialize(app, c.Bool("debug"))
	if err != nil {
		return err
	}

	// Set app routes
	r := mux.NewRouter()
	writefreely.InitRoutes(app, r)
	app.InitStaticRoutes(r)

	// Serve the application
	writefreely.Serve(app, r)

	return nil
}

func parseCredentials(credentialString string) (string, string, error) {
	creds := strings.Split(credentialString, ":")
	if len(creds) != 2 {
		return "", "", fmt.Errorf("invalid format for passed credentials, must be username:password")
	}
	return creds[0], creds[1], nil
}
