//go:build stub
// +build stub

package fvm

import (
	"crypto/tls"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"sync"
)

// Stub FVM implementation for compilation without native C library

var (
	stubMu    sync.Mutex
	stubState = make(map[string][]byte)
)

type FVM struct {
	version int64
}

type FVMUpdate struct {
	data []byte
}

type FVMRe struct {
	data []byte
}

type FVMOutput struct {
	data []byte
}

func New() (*FVM, error) {
	return &FVM{version: 0}, nil
}

func (u *FVMUpdate) ToBytes() []byte {
	return u.data
}

func (u *FVMUpdate) FromBytes(out []byte) error {
	u.data = make([]byte, len(out))
	copy(u.data, out)
	return nil
}

func (u *FVMUpdate) MergeUpdate(patch *FVMUpdate) error {
	stubMu.Lock()
	defer stubMu.Unlock()
	merged := make([]byte, 0, len(u.data)+len(patch.data))
	merged = append(merged, u.data...)
	merged = append(merged, patch.data...)
	u.data = merged
	return nil
}

func (u *FVMUpdate) Release() {
	u.data = nil
}

func (r *FVMRe) ToBytes() []byte {
	return r.data
}

func (r *FVMRe) FromBytes(o []byte) {
	r.data = make([]byte, len(o))
	copy(r.data, o)
}

func (f *FVM) Update(upd *FVMUpdate) error {
	stubMu.Lock()
	defer stubMu.Unlock()
	stubState["current"] = upd.data
	return nil
}

func (f *FVM) Compile(text string, re []byte) (*FVMOutput, *FVMRe, error) {
	// Stub: return empty output
	return &FVMOutput{data: []byte{}}, &FVMRe{data: []byte{}}, nil
}

func (f *FVM) Plot() string {
	return "{}"
}

func (f *FVM) Dump() *FVMUpdate {
	stubMu.Lock()
	defer stubMu.Unlock()
	data := stubState["current"]
	return &FVMUpdate{data: data}
}

func (f *FVM) Release() {}

func Serialize(out *FVMOutput, diff bool, base int64, target int64) *FVMUpdate {
	return &FVMUpdate{data: out.data}
}

func ReleaseOutput(out *FVMOutput) {}

func (f *FVM) PushFsl(server string, update *FVMUpdate) error {
	base, _ := url.Parse(server)
	base.Path = "/update/policy"
	snURL := base.String()

	req, err := http.NewRequest("POST", snURL, nil)
	if err != nil {
		return fmt.Errorf("create request failed: %w", err)
	}
	req.Header.Add("Content-Type", "application/octet-stream")

	httpClient := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		},
	}

	var resp *http.Response
	for i := 0; i < 3; i++ {
		resp, err = httpClient.Do(req)
		if err == nil {
			break
		}
	}
	if err != nil {
		return fmt.Errorf("Get response failed: %w", err)
	}
	if resp != nil && resp.StatusCode != 200 {
		bodyBytes, _ := io.ReadAll(resp.Body)
		return fmt.Errorf("Push FSL response(%d %s)", resp.StatusCode, string(bodyBytes))
	}

	return nil
}
