package main

import (
	"encoding/json"
	"flag"
	"fmt"
)

type listOpts struct {
	jsonMode bool
	page     int
	limit    int
}

func parseListFlags(name string, args []string) (*listOpts, []string, error) {
	fs := flag.NewFlagSet(name, flag.ExitOnError)
	o := &listOpts{}
	fs.BoolVar(&o.jsonMode, "json", false, "emit raw API JSON")
	fs.IntVar(&o.page, "page", 0, "fetch a single page (no auto-pagination)")
	fs.IntVar(&o.limit, "limit", 0, "items per page (100-1000)")
	if err := fs.Parse(args); err != nil {
		return nil, nil, err
	}
	if err := validateLimit(o.limit); err != nil {
		return nil, nil, err
	}
	return o, fs.Args(), nil
}

// fetchList fetches one or all pages of a list endpoint.
// On single-page (`--page` set), singleRaw holds the unmodified body
// so --json can echo it byte-for-byte.
func (c *Client) fetchList(base string, o *listOpts) (items []json.RawMessage, p Paginator, singleRaw []byte, err error) {
	if o.page > 0 {
		err = c.listPaged(base, o.page, o.limit, nil, &singleRaw)
		if err != nil {
			return
		}
		items, p, err = decodeListPage(singleRaw)
		return
	}
	items, p, err = c.listAll(base, o.limit, decodeListPage)
	return
}

func decodeListPage(raw []byte) ([]json.RawMessage, Paginator, error) {
	var resp struct {
		Data      []json.RawMessage `json:"data"`
		Paginator Paginator         `json:"paginator"`
	}
	if err := json.Unmarshal(raw, &resp); err != nil {
		return nil, Paginator{}, err
	}
	return resp.Data, resp.Paginator, nil
}

// emitList prints either raw JSON (single-page or merged) or invokes
// the table renderer over decoded rows.
func emitList(items []json.RawMessage, p Paginator, singleRaw []byte, o *listOpts, table func([]json.RawMessage) error) error {
	if o.jsonMode {
		if singleRaw != nil {
			return printJSON(singleRaw)
		}
		return printMergedJSON(items, p)
	}
	return table(items)
}

// parseGetFlags parses `get` subcommand flags and requires a single ID arg.
func parseGetFlags(name string, args []string) (jsonMode bool, id string, err error) {
	fs := flag.NewFlagSet(name, flag.ExitOnError)
	fs.BoolVar(&jsonMode, "json", false, "emit raw API JSON")
	if e := fs.Parse(args); e != nil {
		err = e
		return
	}
	rest := fs.Args()
	if len(rest) != 1 {
		err = fmt.Errorf("%s: expected exactly one ID argument", name)
		return
	}
	id = rest[0]
	return
}
