// Copyright 2026. Licensed under Apache-2.0. See LICENSE.
// Generated by CLI Printing Press (https://github.com/mvanhorn/cli-printing-press). DO NOT EDIT.

package device

import (
	"context"
	"crypto/rand"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"
)

const sessionCLIName = "ble-session-appliance-pp-cli"

type SessionEndpoint struct {
	Kind string `json:"kind"`
	Path string `json:"path"`
}

type SessionStatus struct {
	Device             string          `json:"device"`
	Mode               string          `json:"mode"`
	State              string          `json:"state"`
	Transport          string          `json:"transport"`
	Endpoint           SessionEndpoint `json:"endpoint"`
	RuntimeDir         string          `json:"runtime_dir"`
	TokenPresent       bool            `json:"token_present"`
	ObservedAt         string          `json:"observed_at"`
	Reasons            []string        `json:"reasons,omitempty"`
	OneShotFallback    bool            `json:"one_shot_fallback"`
	Reconnect          bool            `json:"reconnect"`
	NotificationStream bool            `json:"notification_stream"`
	Detail             string          `json:"detail,omitempty"`
}

type Session interface {
	Start(context.Context) (SessionStatus, error)
	Status(context.Context) (SessionStatus, error)
	Stop(context.Context) (SessionStatus, error)
}

type ReplaySession struct {
	cliName string
}

func NewReplaySession() *ReplaySession {
	return &ReplaySession{cliName: sessionCLIName}
}

func (s *ReplaySession) Start(ctx context.Context) (SessionStatus, error) {
	runtimeDir, err := s.runtimeDir()
	if err != nil {
		return SessionStatus{}, err
	}
	if err := os.MkdirAll(runtimeDir, 0o700); err != nil {
		return SessionStatus{}, fmt.Errorf("create session runtime dir: %w", err)
	}

	lockPath := s.lockPath(runtimeDir)
	lockFile, err := os.OpenFile(lockPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o600)
	if err != nil {
		if os.IsExist(err) {
			return s.statusFromDisk("running", "existing replay session lock is active")
		}
		return SessionStatus{}, fmt.Errorf("create session lock: %w", err)
	}
	defer lockFile.Close()

	token, err := generateSessionToken()
	if err != nil {
		_ = os.Remove(lockPath)
		return SessionStatus{}, err
	}
	if err := os.WriteFile(s.tokenPath(runtimeDir), []byte(token+"\n"), 0o600); err != nil {
		_ = os.Remove(lockPath)
		return SessionStatus{}, fmt.Errorf("write session token: %w", err)
	}

	now := time.Now().UTC()
	record := sessionRecord{
		PID:       os.Getpid(),
		StartedAt: now.Format(time.RFC3339),
		Endpoint:  s.endpoint(runtimeDir),
	}
	if err := json.NewEncoder(lockFile).Encode(record); err != nil {
		_ = os.Remove(lockPath)
		_ = os.Remove(s.tokenPath(runtimeDir))
		return SessionStatus{}, fmt.Errorf("write session lock: %w", err)
	}
	if err := s.writeState(runtimeDir, "running", "replay session runtime started; local IPC endpoint reserved for generated clients"); err != nil {
		_ = os.Remove(lockPath)
		_ = os.Remove(s.tokenPath(runtimeDir))
		return SessionStatus{}, err
	}
	return s.status(runtimeDir, "running", "replay session runtime started; local IPC endpoint reserved for generated clients"), nil
}

func (s *ReplaySession) Status(ctx context.Context) (SessionStatus, error) {
	runtimeDir, err := s.runtimeDir()
	if err != nil {
		return SessionStatus{}, err
	}
	if _, err := os.Stat(s.lockPath(runtimeDir)); err == nil {
		return s.statusFromDisk("running", "replay session runtime is running")
	} else if !os.IsNotExist(err) {
		return SessionStatus{}, fmt.Errorf("stat session lock: %w", err)
	}
	return s.status(runtimeDir, "not-running", "no replay session lock is active"), nil
}

func (s *ReplaySession) Stop(ctx context.Context) (SessionStatus, error) {
	runtimeDir, err := s.runtimeDir()
	if err != nil {
		return SessionStatus{}, err
	}
	if err := os.Remove(s.lockPath(runtimeDir)); err != nil && !os.IsNotExist(err) {
		return SessionStatus{}, fmt.Errorf("remove session lock: %w", err)
	}
	if err := os.Remove(s.tokenPath(runtimeDir)); err != nil && !os.IsNotExist(err) {
		return SessionStatus{}, fmt.Errorf("remove session token: %w", err)
	}
	if err := os.Remove(s.statePath(runtimeDir)); err != nil && !os.IsNotExist(err) {
		return SessionStatus{}, fmt.Errorf("remove session state: %w", err)
	}
	return s.status(runtimeDir, "stopped", "replay session runtime stopped"), nil
}

type sessionRecord struct {
	PID       int             `json:"pid"`
	StartedAt string          `json:"started_at"`
	Endpoint  SessionEndpoint `json:"endpoint"`
}

type sessionStateRecord struct {
	State      string `json:"state"`
	Detail     string `json:"detail"`
	ObservedAt string `json:"observed_at"`
}

func (s *ReplaySession) runtimeDir() (string, error) {
	cacheDir, err := os.UserCacheDir()
	if err != nil {
		return "", fmt.Errorf("resolve user cache dir: %w", err)
	}
	return filepath.Join(cacheDir, s.cliName, "session"), nil
}

func (s *ReplaySession) endpoint(runtimeDir string) SessionEndpoint {
	if runtime.GOOS == "windows" {
		return SessionEndpoint{Kind: "windows-named-pipe", Path: `\\.\pipe\` + sanitizePipeName(s.cliName) + "-session"}
	}
	return SessionEndpoint{Kind: "unix-socket", Path: filepath.Join(runtimeDir, "session.sock")}
}

func (s *ReplaySession) lockPath(runtimeDir string) string {
	return filepath.Join(runtimeDir, "session.lock")
}

func (s *ReplaySession) tokenPath(runtimeDir string) string {
	return filepath.Join(runtimeDir, "capability.token")
}

func (s *ReplaySession) statePath(runtimeDir string) string {
	return filepath.Join(runtimeDir, "state.json")
}

func (s *ReplaySession) writeState(runtimeDir, state, detail string) error {
	record := sessionStateRecord{
		State:      state,
		Detail:     detail,
		ObservedAt: time.Now().UTC().Format(time.RFC3339),
	}
	data, err := json.MarshalIndent(record, "", "  ")
	if err != nil {
		return fmt.Errorf("encode session state: %w", err)
	}
	if err := os.WriteFile(s.statePath(runtimeDir), append(data, '\n'), 0o600); err != nil {
		return fmt.Errorf("write session state: %w", err)
	}
	return nil
}

func (s *ReplaySession) statusFromDisk(fallbackState, fallbackDetail string) (SessionStatus, error) {
	runtimeDir, err := s.runtimeDir()
	if err != nil {
		return SessionStatus{}, err
	}
	state := fallbackState
	detail := fallbackDetail
	if data, err := os.ReadFile(s.statePath(runtimeDir)); err == nil {
		var record sessionStateRecord
		if err := json.Unmarshal(data, &record); err == nil {
			if record.State != "" {
				state = record.State
			}
			if record.Detail != "" {
				detail = record.Detail
			}
		}
	}
	return s.status(runtimeDir, state, detail), nil
}

func (s *ReplaySession) status(runtimeDir, state, detail string) SessionStatus {
	return SessionStatus{
		Device:             DisplayName,
		Mode:               SessionMode,
		State:              state,
		Transport:          "replay",
		Endpoint:           s.endpoint(runtimeDir),
		RuntimeDir:         runtimeDir,
		TokenPresent:       fileExists(s.tokenPath(runtimeDir)),
		ObservedAt:         time.Now().UTC().Format(time.RFC3339),
		Reasons:            append([]string(nil), SessionReasons...),
		OneShotFallback:    SessionOneShotFallback,
		Reconnect:          SessionReconnect,
		NotificationStream: SessionNotificationStream,
		Detail:             detail,
	}
}

func generateSessionToken() (string, error) {
	var raw [32]byte
	if _, err := rand.Read(raw[:]); err != nil {
		return "", fmt.Errorf("generate session token: %w", err)
	}
	return hex.EncodeToString(raw[:]), nil
}

func fileExists(path string) bool {
	_, err := os.Stat(path)
	return err == nil
}

func sanitizePipeName(value string) string {
	value = strings.ToLower(value)
	var b strings.Builder
	for _, r := range value {
		switch {
		case r >= 'a' && r <= 'z':
			b.WriteRune(r)
		case r >= '0' && r <= '9':
			b.WriteRune(r)
		case r == '-' || r == '_':
			b.WriteRune(r)
		default:
			b.WriteRune('-')
		}
	}
	out := strings.Trim(b.String(), "-_")
	if out == "" {
		return "device-session-" + strconv.Itoa(os.Getpid())
	}
	return out
}
