package qmp

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/digitalocean/go-qemu/qmp"
	"github.com/samber/mo"
)

type Client struct {
	monitor qmp.Monitor
}

type VMStatus struct {
	Running    bool
	Singlestep bool
	Status     string
}

func Connect(socketPath string) mo.Result[*Client] {
	monitor, err := qmp.NewSocketMonitor("unix", socketPath, 2*time.Second)
	if err != nil {
		return mo.Err[*Client](fmt.Errorf("failed to create socket monitor: %w", err))
	}

	if err := monitor.Connect(); err != nil {
		return mo.Err[*Client](fmt.Errorf("failed to connect to QMP socket: %w", err))
	}

	return mo.Ok(&Client{monitor: monitor})
}

func (c *Client) Status() mo.Result[VMStatus] {
	type statusResult struct {
		ID     string `json:"id"`
		Return struct {
			Running    bool   `json:"running"`
			Singlestep bool   `json:"singlestep"`
			Status     string `json:"status"`
		} `json:"return"`
	}

	cmd := []byte(`{"execute":"query-status"}`)
	raw, err := c.monitor.Run(cmd)
	if err != nil {
		return mo.Err[VMStatus](fmt.Errorf("failed to execute query-status: %w", err))
	}

	var result statusResult
	if err := json.Unmarshal(raw, &result); err != nil {
		return mo.Err[VMStatus](fmt.Errorf("failed to parse status response: %w", err))
	}

	return mo.Ok(VMStatus{
		Running:    result.Return.Running,
		Singlestep: result.Return.Singlestep,
		Status:     result.Return.Status,
	})
}

func (c *Client) Shutdown() mo.Result[struct{}] {
	cmd := []byte(`{"execute":"system_powerdown"}`)
	_, err := c.monitor.Run(cmd)
	if err != nil {
		return mo.Err[struct{}](fmt.Errorf("failed to execute system_powerdown: %w", err))
	}

	return mo.Ok(struct{}{})
}

func (c *Client) Close() error {
	return c.monitor.Disconnect()
}
