// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
)

const (
	pr = `Must have a Pull Request already open.
  Enter PR # => `

	kind = `Choose type, one of
    1. bug
    2. improvement
    3. security
    4. breaking-change
    5. note
    6. deprecation
  Enter Kind => `

	note = `Write a note, for example
	build: Added make target for creating changelog entries
  Enter Note => `
)

var noteRe = regexp.MustCompile(`^[a-z0-9/\s]+: .+`)

func main() {
	pr, err := ask(pr)
	check(err)

	n, err := ask(kind)
	check(err)

	label, err := label(n)
	check(err)

	body, err := askStr(note)
	check(err)

	msg, err := cleanup(body)
	check(err)

	file, err := write(pr, label, msg)
	check(err)

	fmt.Println("Created", file)
}

func write(pr int, label, msg string) (string, error) {
	filename := filepath.Join(".changelog", fmt.Sprintf("%d.txt", pr))
	sb := new(strings.Builder)
	sb.WriteString("```release-note:")
	sb.WriteString(label)
	sb.WriteString("\n")
	sb.WriteString(msg)
	sb.WriteString("\n")
	sb.WriteString("```\n")
	s := sb.String()
	if err := os.WriteFile(filename, []byte(s), 0o644); err != nil {
		return "", err
	}
	return filename, nil
}

func cleanup(note string) (string, error) {
	note = strings.TrimSpace(note)
	note = strings.TrimSuffix(note, ".")
	if !noteRe.MatchString(note) {
		return "", errors.New("note does not comply with format")
	}
	return note, nil
}

func label(n int) (string, error) {
	var label string
	switch n {
	case 1:
		label = "bug"
	case 2:
		label = "improvement"
	case 3:
		label = "security"
	case 4:
		label = "breaking-change"
	case 5:
		label = "note"
	case 6:
		label = "deprecation"
	default:
		return "", errors.New("not a valid type, must be 1-6")
	}
	return label, nil
}

func ask(q string) (int, error) {
	r := bufio.NewReader(os.Stdin)
	fmt.Print(q)
	line, err := r.ReadString('\n')
	if err != nil {
		return 0, err
	}
	i, err := strconv.Atoi(strings.TrimSpace(line))
	if err != nil {
		return 0, err
	}
	return i, nil
}

func askStr(q string) (string, error) {
	r := bufio.NewReader(os.Stdin)
	fmt.Print(q)
	line, err := r.ReadString('\n')
	return strings.TrimSpace(line), err
}

func check(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "failure: %v\n", err)
		os.Exit(1)
	}
}
