package agent

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/pulse-lets-go/internal/ami"
)

// AsteriskCollector собирает метрики с Asterisk через AMI.
type AsteriskCollector struct {
	client *ami.Client
}

// NewAsteriskCollector создаёт Asterisk-коллектор.
func NewAsteriskCollector(host string, port int, username, password string) *AsteriskCollector {
	return &AsteriskCollector{
		client: ami.NewClient(host, port, username, password),
	}
}

func (ac *AsteriskCollector) Type() string { return "asterisk" }

func (ac *AsteriskCollector) Connect() error {
	return ac.client.Connect()
}

func (ac *AsteriskCollector) Collect() (*PBXResult, error) {
	if !ac.client.IsConnected() {
		return nil, fmt.Errorf("ami не подключён")
	}

	result := &PBXResult{Status: "ok"}

	// active_calls: CoreShowChannels определяет количество активных каналов
	if active, err := ac.coreShowChannelsCount(); err == nil {
		result.ActiveCalls = active
	}

	// max_calls: CoreSettings → CoreMaxCalls
	if max, err := ac.coreSettingsInt("CoreMaxCalls"); err == nil {
		result.MaxCalls = max
	}

	// idle_cpu: Asterisk не даёт FS-шного idle_cpu, используем системный
	result.IdleCPU = 0

	return result, nil
}

func (ac *AsteriskCollector) ListenHangups(onHangup func(success bool)) {
	// Подписываемся на события Hangup через AMI
	ac.client.Subscribe("call")

	go func() {
		for evt := range ac.client.Events() {
			if evt.Headers["Event"] == "Hangup" {
				cause := evt.Headers["Cause"]
				// Считаем успешным только NORMAL_CLEARING (код 16)
				success := cause == "16" || strings.Contains(cause, "NORMAL_CLEARING")
				onHangup(success)
			}
		}
	}()
}

func (ac *AsteriskCollector) Close() {
	ac.client.Disconnect()
}

// --- helpers ---

// coreShowChannelsCount получает количество активных каналов.
func (ac *AsteriskCollector) coreShowChannelsCount() (int, error) {
	cmd := "Action: Command\r\nCommand: core show channels count\r\n"
	headers, body, err := ac.client.SendCommandBody(cmd)
	if err != nil {
		return 0, err
	}
	_ = headers

	// Ответ выглядит как: "1 active call" или "5 active calls"
	body = strings.TrimSpace(body)
	fields := strings.Fields(body)
	if len(fields) >= 3 {
		// Первое слово — число
		n, err := strconv.Atoi(fields[0])
		if err == nil {
			return n, nil
		}
	}
	return 0, fmt.Errorf("не удалось распарсить количество каналов из: %s", body)
}

// coreSettingsInt получает целочисленное значение из CoreSettings.
func (ac *AsteriskCollector) coreSettingsInt(key string) (int, error) {
	headers, _, err := ac.client.SendCommandBody("Action: CoreSettings\r\n")
	if err != nil {
		return 0, err
	}
	val := headers[key]
	if val == "" {
		return 0, fmt.Errorf("поле %s не найдено", key)
	}
	return strconv.Atoi(strings.TrimSpace(val))
}
