// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.

// options.go
package main

import (
	"fmt"
	"io"
	"os"
	"strings"

	"git.portale-stac.it/go-pkg/expr"
	"git.portale-stac.it/go-pkg/expr/kern"
	"git.portale-stac.it/go-pkg/utils"
)

type Options struct {
	printTree        bool
	printPrefix      bool
	forceInteractive bool
	builtin          []any
	expressions      []io.Reader
	formOpt          kern.FmtOpt
	baseVerb         string
	base             int
	output           bool
	rcCount          int
}

func NewOptions() *Options {
	return &Options{
		expressions: make([]io.Reader, 0),
		builtin:     make([]any, 0),
		formOpt:     kern.Base10,
		baseVerb:    "%d",
		base:        10,
		output:      true,
		rcCount:     0,
	}
}

func (opt *Options) loadRc() {
	var rcPath string
	var fh *os.File
	var err error

	rcList := []string{
		".ecli.rc",
		"~/.ecli.rc",
		"~/.config/expr/ecli.rc",
		"~/.dev-expr.rc", // OBSOLETE, to be removed in future releases
	}
	for _, rcFile := range rcList {
		if rcPath, err = utils.ExpandPath(rcFile); err != nil {
			return
		}
		if fh, err = os.Open(rcPath); err == nil {
			opt.expressions = append(opt.expressions, fh) // rc should be the first source to be read
			opt.rcCount++
			break
		}
	}
}

func listBuiltins() {
	expr.IterateBuiltinModules(func(name, description string, imported bool) bool {
		if imported {
			name = "*" + name
		}
		fmt.Printf("%20q: %s\n", name, description)
		return true
	})
}

func (opt *Options) parseArgs() (err error) {
	for i := 1; i < len(os.Args) && err == nil; i++ {
		arg := os.Args[i]
		switch arg {
		case "-i":
			opt.forceInteractive = true
		case "-t":
			opt.printTree = true
		case "-p":
			opt.printPrefix = true
		case "-e":
			if i+1 < len(os.Args) {
				i++
				spec := os.Args[i]
				if strings.HasPrefix(spec, "@") {
					var f *os.File
					if f, err = os.Open(spec[1:]); err == nil {
						opt.expressions = append(opt.expressions, f)
					} else {
						return
					}
				} else {
					if len(spec) > 0 && spec[len(spec)-1] != '\n' {
						spec += "\n"
					}
					opt.expressions = append(opt.expressions, strings.NewReader(spec))
				}
			} else {
				err = errOptValueRequired(arg)
			}
		case "-b":
			if i+1 < len(os.Args) {
				i++
				specs := strings.Split(os.Args[i], ",")
				if len(specs) == 1 {
					opt.builtin = append(opt.builtin, specs[0])
				} else {
					opt.builtin = append(opt.builtin, specs)
				}
			} else {
				err = errOptValueRequired(arg)
			}
		case "-B", "--list-builtins":
			listBuiltins()
			os.Exit(0)
		case "-m", "--modules":
			expr.IterateBuiltinModules(func(name, description string, _ bool) bool {
				fmt.Printf("%20q: %s\n", name, description)
				return true
			})
			os.Exit(0)
		case "--noout":
			opt.output = false
		case "-h", "--help", "help":
			cmdHandler.help()
			os.Exit(0)
		case "-v", "--version", "version", "about":
			fmt.Println(about())
			os.Exit(0)
		default:
			err = fmt.Errorf("invalid option nr %d %q", i+1, arg)
		}
	}
	return
}
