package hostbridge

import (
	"context"
	"log"
	"os"

	"github.com/atotto/clipboard"
	"github.com/cline/cli/pkg/cli/global"
	"github.com/cline/grpc-go/cline"
	"github.com/cline/grpc-go/host"
	"google.golang.org/protobuf/proto"
)

// Global shutdown channel - simple approach
var globalShutdownCh chan struct{}

func init() {
	globalShutdownCh = make(chan struct{})
}

// EnvService implements the host.EnvServiceServer interface
type EnvService struct {
	host.UnimplementedEnvServiceServer
	verbose bool
}

// NewEnvService creates a new EnvService
func NewEnvService(verbose bool) *EnvService {
	return &EnvService{
		verbose: verbose,
	}
}

// ClipboardWriteText writes text to the system clipboard
func (s *EnvService) ClipboardWriteText(ctx context.Context, req *cline.StringRequest) (*cline.Empty, error) {
	if s.verbose {
		log.Printf("ClipboardWriteText called with text length: %d", len(req.GetValue()))
	}

	err := clipboard.WriteAll(req.GetValue())
	if err != nil {
		if s.verbose {
			log.Printf("Failed to write to clipboard: %v", err)
		}
		// Don't fail if clipboard is not available (e.g., headless environment)
	}

	return &cline.Empty{}, nil
}

// ClipboardReadText reads text from the system clipboard
func (s *EnvService) ClipboardReadText(ctx context.Context, req *cline.EmptyRequest) (*cline.String, error) {
	if s.verbose {
		log.Printf("ClipboardReadText called")
	}

	text, err := clipboard.ReadAll()
	if err != nil {
		if s.verbose {
			log.Printf("Failed to read from clipboard: %v", err)
		}
		// Return empty string if clipboard is not available
		text = ""
	}

	return &cline.String{
		Value: text,
	}, nil
}

// GetHostVersion returns the host platform name and version
func (s *EnvService) GetHostVersion(ctx context.Context, req *cline.EmptyRequest) (*host.GetHostVersionResponse, error) {
	if s.verbose {
		log.Printf("GetHostVersion called")
	}

	return &host.GetHostVersionResponse{
		Platform:     proto.String("Cline CLI"),
		Version:      proto.String(global.CliVersion),
		ClineType:    proto.String("CLI"),
		ClineVersion: proto.String(global.CliVersion),
	}, nil
}

// Shutdown initiates a graceful shutdown of the host bridge service
func (s *EnvService) Shutdown(ctx context.Context, req *cline.EmptyRequest) (*cline.Empty, error) {
	if s.verbose {
		log.Printf("Shutdown requested via RPC")
	}

	// Trigger global shutdown signal
	select {
	case globalShutdownCh <- struct{}{}:
		if s.verbose {
			log.Printf("Shutdown signal sent successfully")
		}
	default:
		if s.verbose {
			log.Printf("Shutdown signal already pending")
		}
	}

	return &cline.Empty{}, nil
}

// GetTelemetrySettings returns the telemetry settings for CLI mode
func (s *EnvService) GetTelemetrySettings(ctx context.Context, req *cline.EmptyRequest) (*host.GetTelemetrySettingsResponse, error) {
	if s.verbose {
		log.Printf("GetTelemetrySettings called")
	}

	// In CLI mode, check the POSTHOG_TELEMETRY_ENABLED environment variable
	telemetryEnabled := os.Getenv("POSTHOG_TELEMETRY_ENABLED") == "true"

	var setting host.Setting
	if telemetryEnabled {
		setting = host.Setting_ENABLED
	} else {
		setting = host.Setting_DISABLED
	}

	return &host.GetTelemetrySettingsResponse{
		IsEnabled: setting,
	}, nil
}

// SubscribeToTelemetrySettings returns a stream of telemetry setting changes
// In CLI mode, telemetry settings don't change at runtime, so we just send
// the current state and keep the stream open
func (s *EnvService) SubscribeToTelemetrySettings(req *cline.EmptyRequest, stream host.EnvService_SubscribeToTelemetrySettingsServer) error {
	if s.verbose {
		log.Printf("SubscribeToTelemetrySettings called")
	}

	// Send initial telemetry state
	telemetryEnabled := os.Getenv("POSTHOG_TELEMETRY_ENABLED") == "true"

	var setting host.Setting
	if telemetryEnabled {
		setting = host.Setting_ENABLED
	} else {
		setting = host.Setting_DISABLED
	}

	event := &host.TelemetrySettingsEvent{
		IsEnabled: setting,
	}

	if err := stream.Send(event); err != nil {
		if s.verbose {
			log.Printf("Failed to send telemetry settings event: %v", err)
		}
		return err
	}

	// Keep stream open until context is cancelled
	// (In CLI mode, settings don't change dynamically)
	<-stream.Context().Done()

	if s.verbose {
		log.Printf("SubscribeToTelemetrySettings stream closed")
	}

	return nil
}
