package main
 
import (
	"encoding/json"
	"errors"
	"fmt"
	"regexp"
	"strings"
)
 
var ErrInvalidID = errors.New("invalid ID")
 
type EmptyFieldError struct {
	FieldName string
}
 
func (fe EmptyFieldError) Error() string {
	return fe.FieldName
}
 
func main() {
	d := json.NewDecoder(strings.NewReader(data))
	count := 0
	for d.More() {
		count++
		var emp Employee
		err := d.Decode(&emp)
		if err != nil {
			fmt.Printf("record %d: %v\n", count, err)
			continue
		}
		err = ValidateEmployee(emp)
		if err != nil {
			fmt.Println(err)
			continue
		}
		fmt.Printf("record %d: %+v\n", count, emp)
	}
}
 
const data = `
{
	"id": "ABCD-123",
	"first_name": "Bob",
	"last_name": "Bobson",
	"title": "Senior Manager"
}
{
	"id": "XYZ-123",
	"first_name": "Mary",
	"last_name": "Maryson",
	"title": "Vice President"
}
{
	"id": "BOTX-263",
	"first_name": "",
	"last_name": "Garciason",
	"title": "Manager"
}
{
	"id": "HLXO-829",
	"first_name": "Pierre",
	"last_name": "",
	"title": "Intern"
}
{
	"id": "MOXW-821",
	"first_name": "Franklin",
	"last_name": "Watanabe",
	"title": ""
}
{
	"id": "",
	"first_name": "Shelly",
	"last_name": "Shellson",
	"title": "CEO"
}
{
	"id": "YDOD-324",
	"first_name": "",
	"last_name": "",
	"title": ""
}
`
 
type Employee struct {
	ID        string `json:"id"`
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
	Title     string `json:"title"`
}
 
var (
	validID = regexp.MustCompile(`\w{4}-\d{3}`)
)
 
func ValidateEmployee(e Employee) error {
	var errs []error
 
	if len(e.ID) == 0 {
		errs = append(errs, errors.New("IDがありません"))
	}
	if !validID.MatchString(e.ID) {
		errs = append(errs, errors.New("無効なIDです"))
	}
	if len(e.FirstName) == 0 {
		errs = append(errs, errors.New("名前がありません"))
	}
	if len(e.LastName) == 0 {
		errs = append(errs, errors.New("名字がありません"))
	}
	if len(e.Title) == 0 {
		errs = append(errs, errors.New("タイトルがありません"))
	}
	// エラーの数に応じて、nilを返す場合、ひとつのエラーを返す場合、errors.Joinを使って、ひとつのエラーにすべてのエラーをまとめる場合、に分ける
 	// これはGoのできるだけシンプルにする哲学に従うものである
 	switch len(errs) {
 	case 0:
 		return nil
 	case 1:
 		return errs[0]
 	default:
 		return errors.Join(errs...)
}