// Package notification_proxy implementiert Apple's `com.apple.mobile.notification_proxy`
// für PostNotification-calls. Diese sind nötig vor mobilebackup2-Restore
// damit iOS den Restore als "legitimate iTunes-style sync" akzeptiert.
//
// Reverse-engineered aus TechLockdown's safesurfer.go calls — TL ruft
// postNotification VOR + NACH dem mobilebackup2-Restore-Block.
//
// Wire-Format: 4-byte BE length-prefix + XML plist (dict).
package notification_proxy

import (
	"encoding/binary"
	"fmt"

	ios "github.com/danielpaulus/go-ios/ios"
)

const serviceName = "com.apple.mobile.notification_proxy"

// Apple's standard sync notifications die iOS während iTunes-style sync erwartet.
const (
	SyncWillStart    = "com.apple.itunes-mobdev.syncWillStart"
	SyncDidStart     = "com.apple.itunes-mobdev.syncDidStart"
	SyncLockRequest  = "com.apple.itunes-mobdev.syncLockRequest"
	SyncDidFinish    = "com.apple.itunes-mobdev.syncDidFinish"
	BackupDomainChanged = "com.apple.mobile.backup.domain_changed"
)

type Client struct {
	conn  ios.DeviceConnectionInterface
	codec ios.PlistCodec
}

// Open startet die notification-proxy session via Lockdown.
func Open(device ios.DeviceEntry) (*Client, error) {
	conn, err := ios.ConnectToService(device, serviceName)
	if err != nil {
		return nil, fmt.Errorf("notification_proxy: connect: %w", err)
	}
	return &Client{
		conn:  conn,
		codec: ios.NewPlistCodec(),
	}, nil
}

func (c *Client) Close() error {
	if c.conn != nil {
		return c.conn.Close()
	}
	return nil
}

// PostOnce — convenience: open NP, send PostNotification, close. Vermeidet
// connection-sharing-issues mit anderen Services über usbmuxd-socket.
func PostOnce(device ios.DeviceEntry, name string) error {
	c, err := Open(device)
	if err != nil {
		return err
	}
	defer c.Close()
	return c.PostNotification(name)
}

// PostNotification triggert eine system-weite Notification auf iOS.
// iOS-Subsystems die diese Notification subscribed haben werden geweckt.
func (c *Client) PostNotification(name string) error {
	msg := map[string]interface{}{
		"Command": "PostNotification",
		"Name":    name,
	}
	encoded, err := c.codec.Encode(msg)
	if err != nil {
		return fmt.Errorf("notification_proxy: encode: %w", err)
	}
	// Apple's NP-service erwartet 4-byte BE length-prefix + plist-bytes
	hdr := make([]byte, 4)
	binary.BigEndian.PutUint32(hdr, uint32(len(encoded)))
	if err := c.conn.Send(hdr); err != nil {
		return fmt.Errorf("notification_proxy: send header: %w", err)
	}
	if err := c.conn.Send(encoded); err != nil {
		return fmt.Errorf("notification_proxy: send payload: %w", err)
	}
	return nil
}
