package main import ( "context" "encoding/json" "flag" "fmt" "os" "text/tabwriter" "gitea.lab.audasmedia.com.au/sam/compass_teams_nhs/internal/config" "gitea.lab.audasmedia.com.au/sam/compass_teams_nhs/internal/store" ) // codesCommand is the `school codes` entry point: the editable decode map for // Compass periods (AGENTS.md ยง4 FR-17). An unknown code renders as the raw // code, so a missing entry is safe but unreadable; this is how Sam corrects it. func codesCommand(args []string) { if len(args) == 0 { usage("school codes list [--kind KIND] | set --kind KIND --code CODE --name NAME | delete --kind KIND --code CODE") } switch args[0] { case "list": codesList(args[1:]) case "set": codesSet(args[1:]) case "delete": codesDelete(args[1:]) default: usage("school codes list | set | delete") } } func openCodes(ctx context.Context) (*store.Store, error) { cfg, err := config.LoadDB() if err != nil { return nil, err } st, err := store.Open(cfg.DBPath) if err != nil { return nil, err } if err := st.Migrate(ctx); err != nil { _ = st.Close() return nil, err } if err := st.SeedCodes(ctx); err != nil { _ = st.Close() return nil, err } return st, nil } func codesList(args []string) { fs := flag.NewFlagSet("codes list", flag.ContinueOnError) var ( kind string asJSON bool ) fs.StringVar(&kind, "kind", "", "limit to subject, room, teacher or period") fs.BoolVar(&asJSON, "json", false, "print as JSON") _ = fs.Parse(args) ctx := context.Background() st, err := openCodes(ctx) if err != nil { fmt.Fprintln(os.Stderr, "school codes:", err) os.Exit(1) } defer st.Close() codes, err := st.ListCodes(ctx) if err != nil { fmt.Fprintln(os.Stderr, "school codes:", err) os.Exit(1) } if kind != "" { filtered := codes[:0] for _, c := range codes { if c.Kind == kind { filtered = append(filtered, c) } } codes = filtered } if asJSON { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") if err := enc.Encode(codes); err != nil { fmt.Fprintln(os.Stderr, "school codes:", err) os.Exit(1) } return } tw := tabwriter.NewWriter(os.Stdout, 0, 4, 2, ' ', 0) fmt.Fprintln(tw, "KIND\tCODE\tREADS AS") for _, c := range codes { fmt.Fprintf(tw, "%s\t%s\t%s\n", c.Kind, c.Code, c.Name) } _ = tw.Flush() } func codesSet(args []string) { fs := flag.NewFlagSet("codes set", flag.ContinueOnError) var kind, code, name string fs.StringVar(&kind, "kind", "", "subject, room, teacher or period") fs.StringVar(&code, "code", "", "the raw Compass code") fs.StringVar(&name, "name", "", "the plain-English name") _ = fs.Parse(args) if kind == "" || code == "" || name == "" { fmt.Fprintln(os.Stderr, "school codes set: --kind, --code and --name are required") os.Exit(2) } ctx := context.Background() st, err := openCodes(ctx) if err != nil { fmt.Fprintln(os.Stderr, "school codes:", err) os.Exit(1) } defer st.Close() c, err := st.SetCode(ctx, kind, code, name) if err != nil { fmt.Fprintln(os.Stderr, "school codes:", err) os.Exit(1) } fmt.Printf("%s %s reads as %q\n", c.Kind, c.Code, c.Name) } func codesDelete(args []string) { fs := flag.NewFlagSet("codes delete", flag.ContinueOnError) var kind, code string fs.StringVar(&kind, "kind", "", "subject, room, teacher or period") fs.StringVar(&code, "code", "", "the raw Compass code") _ = fs.Parse(args) if kind == "" || code == "" { fmt.Fprintln(os.Stderr, "school codes delete: --kind and --code are required") os.Exit(2) } ctx := context.Background() st, err := openCodes(ctx) if err != nil { fmt.Fprintln(os.Stderr, "school codes:", err) os.Exit(1) } defer st.Close() ok, err := st.DeleteCode(ctx, kind, code) if err != nil { fmt.Fprintln(os.Stderr, "school codes:", err) os.Exit(1) } if !ok { fmt.Printf("%s %s was not mapped\n", kind, code) return } fmt.Printf("%s %s now renders as the raw code\n", kind, code) }