// Monitor capture for full screen or monitor region capture (cross-platform).
package backends

import (
	"fmt"
	"image"
	"runtime"

	"git.cloonar.com/openclawd/iso-bot/pkg/engine/capture"
)

// MonitorConfig holds configuration for monitor capture.
type MonitorConfig struct {
	// MonitorIndex specifies which monitor to capture (0-based).
	// -1 captures the primary monitor.
	MonitorIndex int `yaml:"monitor_index"`

	// Region defines a specific area to capture.
	// If nil, captures the entire monitor.
	Region *capture.Region `yaml:"region"`

	// IncludeCursor captures the mouse cursor.
	IncludeCursor bool `yaml:"include_cursor"`

	// Method specifies the capture method.
	// Options: "auto", "gdi", "dxgi", "x11", "wayland"
	Method string `yaml:"method"`
}

// MonitorSource captures from a monitor or screen region.
type MonitorSource struct {
	config      MonitorConfig
	monitors    []MonitorInfo
	activeIndex int
	width       int
	height      int
	impl        MonitorCaptureImpl
}

// MonitorInfo describes a display monitor.
type MonitorInfo struct {
	Index    int
	Name     string
	X        int
	Y        int
	Width    int
	Height   int
	Primary  bool
	ScaleFactor float64
}

// MonitorCaptureImpl defines platform-specific capture implementation.
type MonitorCaptureImpl interface {
	Initialize() error
	CaptureMonitor(monitor MonitorInfo, region *capture.Region) (image.Image, error)
	Close() error
}

// NewMonitorSource creates a monitor capture source.
func NewMonitorSource(configMap map[string]interface{}) (capture.Source, error) {
	var config MonitorConfig

	// Extract config from map
	if index, ok := configMap["monitor_index"].(int); ok {
		config.MonitorIndex = index
	} else {
		config.MonitorIndex = -1 // Primary monitor
	}

	if regionMap, ok := configMap["region"].(map[string]interface{}); ok {
		region := &capture.Region{}
		if x, ok := regionMap["x"].(int); ok {
			region.X = x
		}
		if y, ok := regionMap["y"].(int); ok {
			region.Y = y
		}
		if width, ok := regionMap["width"].(int); ok {
			region.Width = width
		}
		if height, ok := regionMap["height"].(int); ok {
			region.Height = height
		}
		config.Region = region
	}

	if cursor, ok := configMap["include_cursor"].(bool); ok {
		config.IncludeCursor = cursor
	} else {
		config.IncludeCursor = true
	}

	if method, ok := configMap["method"].(string); ok {
		config.Method = method
	} else {
		config.Method = "auto"
	}

	source := &MonitorSource{
		config: config,
	}

	// Initialize platform-specific implementation
	if err := source.initImpl(); err != nil {
		return nil, fmt.Errorf("failed to initialize monitor capture: %w", err)
	}

	return source, nil
}

// Name returns a description of this capture source.
func (m *MonitorSource) Name() string {
	if m.config.MonitorIndex >= 0 {
		return fmt.Sprintf("Monitor %d", m.config.MonitorIndex)
	}
	return "Primary Monitor"
}

// Capture grabs a single frame from the monitor.
func (m *MonitorSource) Capture() (image.Image, error) {
	if m.impl == nil {
		return nil, fmt.Errorf("monitor capture not initialized")
	}

	monitor, err := m.getTargetMonitor()
	if err != nil {
		return nil, err
	}

	return m.impl.CaptureMonitor(monitor, m.config.Region)
}

// CaptureRegion grabs a sub-region of the monitor.
func (m *MonitorSource) CaptureRegion(r capture.Region) (image.Image, error) {
	if m.impl == nil {
		return nil, fmt.Errorf("monitor capture not initialized")
	}

	monitor, err := m.getTargetMonitor()
	if err != nil {
		return nil, err
	}

	return m.impl.CaptureMonitor(monitor, &r)
}

// Size returns the monitor dimensions.
func (m *MonitorSource) Size() (width, height int) {
	if m.config.Region != nil {
		return m.config.Region.Width, m.config.Region.Height
	}
	return m.width, m.height
}

// Close releases monitor capture resources.
func (m *MonitorSource) Close() error {
	if m.impl != nil {
		return m.impl.Close()
	}
	return nil
}

// initImpl initializes the platform-specific capture implementation.
func (m *MonitorSource) initImpl() error {
	var impl MonitorCaptureImpl
	var err error

	// Choose implementation based on platform and method
	switch {
	case m.config.Method == "auto":
		impl, err = m.createAutoImpl()
	case m.config.Method == "gdi" && runtime.GOOS == "windows":
		impl, err = NewGDICapture(m.config)
	case m.config.Method == "dxgi" && runtime.GOOS == "windows":
		impl, err = NewDXGICapture(m.config)
	case m.config.Method == "x11" && runtime.GOOS == "linux":
		impl, err = NewX11MonitorCapture(m.config)
	case m.config.Method == "wayland" && runtime.GOOS == "linux":
		impl, err = NewWaylandMonitorCapture(m.config)
	default:
		return fmt.Errorf("unsupported capture method %q for platform %s", m.config.Method, runtime.GOOS)
	}

	if err != nil {
		return err
	}

	m.impl = impl
	return m.impl.Initialize()
}

// createAutoImpl selects the best implementation for the current platform.
func (m *MonitorSource) createAutoImpl() (MonitorCaptureImpl, error) {
	switch runtime.GOOS {
	case "windows":
		// Prefer DXGI for better performance, fallback to GDI
		if impl, err := NewDXGICapture(m.config); err == nil {
			return impl, nil
		}
		return NewGDICapture(m.config)
	case "linux":
		// Try Wayland first, fallback to X11
		if impl, err := NewWaylandMonitorCapture(m.config); err == nil {
			return impl, nil
		}
		return NewX11MonitorCapture(m.config)
	case "darwin":
		return NewMacOSCapture(m.config)
	default:
		return nil, fmt.Errorf("unsupported platform: %s", runtime.GOOS)
	}
}

// getTargetMonitor returns the monitor to capture based on configuration.
func (m *MonitorSource) getTargetMonitor() (MonitorInfo, error) {
	if len(m.monitors) == 0 {
		return MonitorInfo{}, fmt.Errorf("no monitors detected")
	}

	if m.config.MonitorIndex == -1 {
		// Find primary monitor
		for _, monitor := range m.monitors {
			if monitor.Primary {
				return monitor, nil
			}
		}
		// If no primary found, use first monitor
		return m.monitors[0], nil
	}

	if m.config.MonitorIndex >= len(m.monitors) {
		return MonitorInfo{}, fmt.Errorf("monitor index %d out of range (have %d monitors)", m.config.MonitorIndex, len(m.monitors))
	}

	return m.monitors[m.config.MonitorIndex], nil
}

// enumerateMonitors discovers available monitors.
func (m *MonitorSource) enumerateMonitors() error {
	// TODO: Implement monitor enumeration for each platform
	// This would use platform-specific APIs to discover monitors
	m.monitors = []MonitorInfo{
		{
			Index:   0,
			Name:    "Primary Display",
			X:       0,
			Y:       0,
			Width:   1920,
			Height:  1080,
			Primary: true,
			ScaleFactor: 1.0,
		},
	}
	return nil
}

// Platform-specific capture implementations (stubs for now)

// NewGDICapture creates a GDI-based capture implementation for Windows.
func NewGDICapture(config MonitorConfig) (MonitorCaptureImpl, error) {
	// TODO: Implement GDI capture using GetDC/BitBlt
	return &GDICapture{config: config}, nil
}

// NewDXGICapture creates a DXGI-based capture implementation for Windows.
func NewDXGICapture(config MonitorConfig) (MonitorCaptureImpl, error) {
	// TODO: Implement DXGI Desktop Duplication API capture
	return &DXGICapture{config: config}, nil
}

// NewX11MonitorCapture creates an X11-based capture implementation for Linux.
func NewX11MonitorCapture(config MonitorConfig) (MonitorCaptureImpl, error) {
	// TODO: Implement X11 root window capture using XGetImage
	return &X11MonitorCapture{config: config}, nil
}

// NewWaylandMonitorCapture creates a Wayland-based capture implementation for Linux.
func NewWaylandMonitorCapture(config MonitorConfig) (MonitorCaptureImpl, error) {
	// TODO: Implement Wayland capture using PipeWire/xdg-desktop-portal
	return &WaylandMonitorCapture{config: config}, nil
}

// NewMacOSCapture creates a macOS capture implementation.
func NewMacOSCapture(config MonitorConfig) (MonitorCaptureImpl, error) {
	// TODO: Implement macOS capture using CGDisplayCreateImage
	return &MacOSCapture{config: config}, nil
}

// Stub implementations
type GDICapture struct{ config MonitorConfig }
func (g *GDICapture) Initialize() error { return fmt.Errorf("GDI capture not implemented") }
func (g *GDICapture) CaptureMonitor(monitor MonitorInfo, region *capture.Region) (image.Image, error) { return nil, fmt.Errorf("GDI capture not implemented") }
func (g *GDICapture) Close() error { return nil }

type DXGICapture struct{ config MonitorConfig }
func (d *DXGICapture) Initialize() error { return fmt.Errorf("DXGI capture not implemented") }
func (d *DXGICapture) CaptureMonitor(monitor MonitorInfo, region *capture.Region) (image.Image, error) { return nil, fmt.Errorf("DXGI capture not implemented") }
func (d *DXGICapture) Close() error { return nil }

type X11MonitorCapture struct{ config MonitorConfig }
func (x *X11MonitorCapture) Initialize() error { return fmt.Errorf("X11 monitor capture not implemented") }
func (x *X11MonitorCapture) CaptureMonitor(monitor MonitorInfo, region *capture.Region) (image.Image, error) { return nil, fmt.Errorf("X11 monitor capture not implemented") }
func (x *X11MonitorCapture) Close() error { return nil }

type WaylandMonitorCapture struct{ config MonitorConfig }
func (w *WaylandMonitorCapture) Initialize() error { return fmt.Errorf("Wayland monitor capture not implemented") }
func (w *WaylandMonitorCapture) CaptureMonitor(monitor MonitorInfo, region *capture.Region) (image.Image, error) { return nil, fmt.Errorf("Wayland monitor capture not implemented") }
func (w *WaylandMonitorCapture) Close() error { return nil }

type MacOSCapture struct{ config MonitorConfig }
func (m *MacOSCapture) Initialize() error { return fmt.Errorf("macOS capture not implemented") }
func (m *MacOSCapture) CaptureMonitor(monitor MonitorInfo, region *capture.Region) (image.Image, error) { return nil, fmt.Errorf("macOS capture not implemented") }
func (m *MacOSCapture) Close() error { return nil }