package main

import (
	"fmt"

	"github.com/golang/protobuf/proto"
	"github.com/pkg/errors"
	"github.com/urfave/cli"

	"code.justin.tv/dta/rockpaperscissors/client/blueprint"
	"code.justin.tv/dta/rockpaperscissors/client/projectmetadata"
	pb "code.justin.tv/dta/rockpaperscissors/proto"
)

func init() {
	var client *projectmetadata.Client
	beforeFunc := func(c *cli.Context) error {
		var err error
		client, err = projectmetadata.NewClient(c.GlobalString("rps-addr"))
		if err != nil {
			return errors.Wrap(err, "Did not connect")
		}
		return nil
	}
	afterFunc := func(c *cli.Context) error {
		if client == nil {
			return nil
		}
		if err := client.Close(); err != nil {
			return err
		}
		return nil
	}

	projectsCmd := cli.Command{
		Name:   "projects",
		Usage:  "commands related to project metadata",
		Before: beforeFunc,
		After:  afterFunc,
		Subcommands: []cli.Command{
			{
				Name:  "list",
				Usage: "list all project IDs",
				Action: func(c *cli.Context) error {
					return printProjectList(client)
				},
			},
			{
				Name:      "get",
				Usage:     "get project metadata of given project ID",
				ArgsUsage: "PROJECTID",
				Flags: []cli.Flag{
					cli.BoolFlag{
						Name:  "as-template",
						Usage: "Format the output like an enroll template",
					},
				},
				Action: func(c *cli.Context) error {
					projectID := c.Args().Get(0)
					if len(projectID) == 0 {
						return errors.New("project ID argument is required")
					}
					return printProject(client, projectID, c.Bool("as-template"))
				},
			},
			{
				Name:      "update",
				Usage:     "update project metadata with a text-formatted protobuf file",
				ArgsUsage: "FILE",
				Action: func(c *cli.Context) error {
					protoFilename := c.Args().Get(0)
					if len(protoFilename) == 0 {
						return errors.New(
							"filename for a text-formated ProjectMetadata protobuf is required")
					}
					projectMetadata, err := blueprint.ReadFile(protoFilename)
					if err != nil {
						return err
					}
					return updateProject(client, projectMetadata)
				},
			},
			{
				Name:      "ingest",
				Usage:     "ingest a blueprint file from GitHub",
				ArgsUsage: "--repo REPO --path BLUEPRINT",
				Flags: []cli.Flag{
					cli.StringFlag{
						Name:  "repo",
						Usage: "GitHub repository like \"org/name\"",
					},
					cli.StringFlag{
						Name:  "path",
						Usage: "Path to a blueprint file within the repository",
					},
					cli.StringFlag{
						Name:  "host",
						Value: "git-aws.internal.justin.tv",
						Usage: "GitHub instance hostname",
					},
				},
				Action: func(c *cli.Context) error {
					repo := c.String("repo")
					if len(repo) == 0 {
						return errors.New("repo argument is required")
					}
					path := c.String("path")
					if len(path) == 0 {
						return errors.New("path argument is required")
					}
					host := c.String("host")
					return ingestBlueprint(client, repo, path, host)
				},
			},
		},
	}
	app.Commands = append(app.Commands, projectsCmd)
}

func printProjectList(client *projectmetadata.Client) error {
	projects, err := client.ListProjects(false)
	if err != nil {
		return errors.Wrap(err, "Could not list projects")
	}
	for _, project := range projects {
		fmt.Printf("%s: %s\n", project.GetProjectId(), project.GetProjectName())
	}
	return nil
}

func printProject(client *projectmetadata.Client, projectID string, asTemplate bool) error {
	project, err := client.GetMetadata(projectID)
	if err != nil {
		return errors.Wrap(err, "Could not get metadata")
	}
	if asTemplate {
		content, err := blueprint.MakeTemplate(project)
		if err != nil {
			return err
		}
		fmt.Print(content)
	} else {
		fmt.Print(proto.MarshalTextString(project))
	}
	return nil
}

func updateProject(client *projectmetadata.Client, projectMetadata *pb.ProjectMetadata) error {
	err := client.UpdateMetadata(projectMetadata)
	if err != nil {
		return errors.Wrap(err, "Could not update project")
	}
	return nil
}

func ingestBlueprint(client *projectmetadata.Client, repo string, path string, host string) error {
	err := client.IngestBlueprint(repo, path, host)
	if err != nil {
		return errors.Wrap(err, "Could not ingest blueprint")
	}
	return nil
}
