// Package connection owns the secret-free, server-verified capability
// document stored in a generic Email Connection.
package connection

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
)

// Config is the capability material stored in generic Connection config.
type Config struct {
	SchemaVersion         int      `json:"schemaVersion"`
	SenderAddress         string   `json:"senderAddress"`
	SenderAddressAccepted bool     `json:"senderAddressAccepted"`
	IMAP                  Endpoint `json:"imap"`
	SMTP                  Endpoint `json:"smtp"`
	CapabilityDigest      string   `json:"capabilityDigest"`
}

// Endpoint is one verified protocol endpoint and its canonical capability set.
type Endpoint struct {
	Host         string   `json:"host"`
	Port         int      `json:"port"`
	TLSMode      string   `json:"tlsMode"`
	Capabilities []string `json:"capabilities"`
	DraftMailbox string   `json:"draftMailbox,omitempty"`
}

// ComputeDigest binds every capability-bearing config field except the digest
// itself. All writers and readers use this one canonical representation.
func (config Config) ComputeDigest() (string, error) {
	payload, err := json.Marshal(config.digestDocument())
	if err != nil {
		return "", fmt.Errorf("encode Email capabilities: %w", err)
	}
	sum := sha256.Sum256(payload)
	return "sha256:" + hex.EncodeToString(sum[:]), nil
}

// VerifyDigest rejects stale or partially rewritten capability material.
func (config Config) VerifyDigest() error {
	expected, err := config.ComputeDigest()
	if err != nil {
		return err
	}
	if expected != config.CapabilityDigest {
		return fmt.Errorf("Email Connection capability digest is invalid")
	}
	return nil
}

// JSONObject returns the exact generic Connection config document.
func (config Config) JSONObject() map[string]any {
	document := config.digestDocument()
	document["capabilityDigest"] = config.CapabilityDigest
	return document
}

func (config Config) digestDocument() map[string]any {
	return map[string]any{
		"schemaVersion":         config.SchemaVersion,
		"senderAddress":         config.SenderAddress,
		"senderAddressAccepted": config.SenderAddressAccepted,
		"imap": map[string]any{
			"host":         config.IMAP.Host,
			"port":         config.IMAP.Port,
			"tlsMode":      config.IMAP.TLSMode,
			"capabilities": append([]string(nil), config.IMAP.Capabilities...),
			"draftMailbox": config.IMAP.DraftMailbox,
		},
		"smtp": map[string]any{
			"host":         config.SMTP.Host,
			"port":         config.SMTP.Port,
			"tlsMode":      config.SMTP.TLSMode,
			"capabilities": append([]string(nil), config.SMTP.Capabilities...),
		},
	}
}
