package cl_104

import (
	"encoding/json"
	"errors"
	"strconv"
	"sync"
	"time"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/metric"
	"github.com/influxdata/telegraf/plugins/parsers"
)

// Parser
type Parser struct {
	DefaultMetricName string
	DefaultTags       map[string]string
	Log               telegraf.Logger

	// **** The struct fields below this comment are used for processing individual configs ****

	// measurementName is the name of the current config used in each line protocol
	measurementName string

	// parseMutex is here because Parse() is not threadsafe.  If it is made threadsafe at some point, then we won't need it anymore.
	parseMutex sync.Mutex
}

type info struct {
	IOA int     `json:"ioa"`
	Val float64 `json:"val"`
	Q   int     `json:"q"`
	MS  int64   `json:"ms"`
}

type msg struct {
	TI    int     `json:"ti"`
	COT   int     `json:"cot"`
	PN    int     `json:"pn"`
	CA    int     `json:"ca"`
	Infos []*info `json:"infos"`
}

func (p *Parser) Init() error {
	if len(p.measurementName) == 0 {
		p.measurementName = "cl104"
	}
	return nil
}

func (p *Parser) Parse(input []byte) ([]telegraf.Metric, error) {
	msg := new(msg)
	if err := json.Unmarshal(input, msg); err != nil {
		return nil, err
	}

	metrics := make([]telegraf.Metric, 0, len(msg.Infos))
	for _, info := range msg.Infos {
		if info == nil {
			continue
		}

		tags := map[string]string{
			"ca":  strconv.Itoa(msg.CA),
			"cot": strconv.Itoa(msg.COT),
			"ioa": strconv.Itoa(info.IOA),
			"ti":  strconv.Itoa(msg.TI),
		}

		fields := map[string]any{
			"val": info.Val,
		}

		tm := time.Now()
		if info.MS > 0 {
			tm = time.UnixMilli(info.MS)
		}

		metrics = append(metrics, metric.New(
			p.measurementName,
			tags,
			fields,
			tm,
		))
	}

	return metrics, nil
}

func (*Parser) ParseLine(string) (telegraf.Metric, error) {
	return nil, errors.New("parsing line is not implemented")
}

func (p *Parser) SetDefaultTags(tags map[string]string) {
	p.DefaultTags = tags
}

func init() {
	// Register all variants
	parsers.Add("cl_104",
		func(defaultMetricName string) telegraf.Parser {
			return &Parser{
				DefaultMetricName: defaultMetricName,
				measurementName:   "cl104",
			}
		},
	)
}
