package tunnel

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"time"
)

const stateFile = "tunnel-state.json"

// State tracks the cp9 C1 tunnel contract for a session.
type State struct {
	Mechanism        string    `json:"mechanism"`
	Owner            string    `json:"owner"`
	Profile          string    `json:"profile,omitempty"`
	Region           string    `json:"region,omitempty"`
	Account          string    `json:"account,omitempty"`
	Healthy          bool      `json:"healthy"`
	ObservedEgressIP string    `json:"observed_egress_ip,omitempty"`
	CheckedAt        time.Time `json:"checked_at"`
}

func StatePath(stateDir string) string {
	return filepath.Join(stateDir, stateFile)
}

func SaveState(stateDir string, state *State) error {
	if err := os.MkdirAll(stateDir, 0o755); err != nil {
		return fmt.Errorf("create tunnel state dir: %w", err)
	}
	if state.CheckedAt.IsZero() {
		state.CheckedAt = time.Now()
	}
	data, err := json.MarshalIndent(state, "", "  ")
	if err != nil {
		return fmt.Errorf("marshal tunnel state: %w", err)
	}
	tmp, err := os.CreateTemp(stateDir, "tunnel-state.*.tmp")
	if err != nil {
		return fmt.Errorf("create tunnel state temp file: %w", err)
	}
	tmpPath := tmp.Name()
	defer os.Remove(tmpPath)
	if _, err := tmp.Write(data); err != nil {
		_ = tmp.Close()
		return fmt.Errorf("write tunnel state temp file: %w", err)
	}
	if err := tmp.Close(); err != nil {
		return fmt.Errorf("close tunnel state temp file: %w", err)
	}
	if err := os.Rename(tmpPath, StatePath(stateDir)); err != nil {
		return fmt.Errorf("rename tunnel state file: %w", err)
	}
	return nil
}

func LoadState(stateDir string) (*State, error) {
	data, err := os.ReadFile(StatePath(stateDir))
	if err != nil {
		return nil, fmt.Errorf("read tunnel state file: %w", err)
	}
	var state State
	if err := json.Unmarshal(data, &state); err != nil {
		return nil, fmt.Errorf("parse tunnel state file: %w", err)
	}
	return &state, nil
}
