package db

import (
	"encoding/json"
	"time"
)

// Mailbox is a real, IMAP-retrievable local mailbox — distinct from Sender (which is
// relay/auth-only). PasswordHash authenticates the self-service web portal only;
// IMAP/SMTP client login always goes through a MailboxAppPassword instead.
type Mailbox struct {
	ID           int64
	Email        string
	DomainID     int64
	PasswordHash string
	IsActive     bool
	QuotaBytes   int64
	UsedBytes    int64
	DEKWrapped   []byte
	DEKNonce     []byte
	CreatedAt    time.Time
	CreatedBy    *int64
	TOTPSecret   string
	TOTPEnabled  bool
	// MFAExempt overrides [Auth] enforce_mailbox_mfa off for this mailbox specifically,
	// even if its domain isn't exempt.
	MFAExempt bool
}

// MailboxSession is a self-service webmail portal login — a parallel schema to
// AdminSession, not shared (see esrv_mailbox_sessions in schema.go).
type MailboxSession struct {
	Token       string
	MailboxID   int64
	MFAVerified bool
	CreatedAt   time.Time
	ExpiresAt   time.Time
}

// MailboxWebAuthnCredential is a mailbox owner's passkey — a parallel schema to
// WebAuthnCredential, not shared.
type MailboxWebAuthnCredential struct {
	ID             int64
	MailboxID      int64
	Name           string
	CredentialID   string
	CredentialData string
	CreatedAt      time.Time
}

// MailboxAlias is an alternate address for a mailbox — receive-only by default, or
// also usable as MAIL FROM once authenticated (CanSendAs). Login is always the
// mailbox's own primary address, never an alias.
type MailboxAlias struct {
	ID        int64
	MailboxID int64
	Email     string
	DomainID  int64
	CanSendAs bool
	IsActive  bool
	CreatedAt time.Time
}

// MailboxAllowBlockEntry is one allow- or block-list pattern for a mailbox.
type MailboxAllowBlockEntry struct {
	ID        int64
	MailboxID int64
	ListType  string // "allow" | "block"
	Pattern   string
	CreatedAt time.Time
}

// MailboxFilterRule is one priority-ordered, first-match-wins delivery rule.
// ConditionField/Op/Value are the legacy single-condition columns; ConditionsJSON
// (when non-empty) is the current multi-condition representation — see Conditions().
type MailboxFilterRule struct {
	ID             int64
	MailboxID      int64
	Priority       int
	ConditionField string // "from" | "to" | "subject"
	ConditionOp    string // "contains" | "equals" | "starts_with"
	ConditionValue string
	Action         string // "move_to_folder" | "delete" | "mark_read" | "mark_as_spam"
	ActionValue    string
	IsActive       bool
	ConditionsJSON string
	MatchType      string // "all" (AND, default) | "any" (OR)
	CreatedAt      time.Time
}

// RuleCondition is one condition within a filter rule's "if" clause.
type RuleCondition struct {
	Field string `json:"field"`
	Op    string `json:"op"`
	Value string `json:"value"`
}

// Conditions returns this rule's conditions and how they combine ("all"=AND,
// "any"=OR) — parses ConditionsJSON when present, falling back to the single legacy
// condition_field/op/value columns for rules created before multi-condition support
// existed. Shared by mailstore.ApplyRules (evaluation) and the webui (display), so
// both stay in sync with the same fallback rule.
func (r MailboxFilterRule) Conditions() ([]RuleCondition, string) {
	if r.ConditionsJSON != "" {
		var parsed []RuleCondition
		if err := json.Unmarshal([]byte(r.ConditionsJSON), &parsed); err == nil && len(parsed) > 0 {
			matchType := r.MatchType
			if matchType != "any" {
				matchType = "all"
			}
			return parsed, matchType
		}
	}
	return []RuleCondition{{Field: r.ConditionField, Op: r.ConditionOp, Value: r.ConditionValue}}, "all"
}

// MailboxAppPassword is the only credential an IMAP/SMTP client ever uses. Plaintext
// is shown once at creation and never stored. ExpiresAt is nil for a password that
// never expires (the default).
type MailboxAppPassword struct {
	ID           int64
	MailboxID    int64
	Label        string
	PasswordHash string
	IsActive     bool
	CreatedAt    time.Time
	LastUsedAt   *time.Time
	ExpiresAt    *time.Time
}

// MailboxMessage is one stored message. CachedFrom/CachedTo/CachedSubject are
// plaintext by design (see schema.go); the rest of the message lives encrypted at
// StoragePath. CachedTo exists purely so folder listings (e.g. Sent) can show the
// recipient without decrypting every message just to render a list.
type MailboxMessage struct {
	ID              int64
	MailboxID       int64
	Folder          string
	MessageIDHeader string
	Flags           string
	InternalDate    time.Time
	SizeBytes       int64
	CachedFrom      string
	CachedTo        string
	CachedSubject   string
	StoragePath     string
	Nonce           []byte
	CreatedAt       time.Time
}

// MailboxSMIMEIdentity is one of a mailbox's own S/MIME certificate + private key
// pairs — a mailbox may hold several. Both halves are stored plain: S/MIME is
// sign-only in this codebase, so the key never protects anything beyond what the
// server already has access to.
type MailboxSMIMEIdentity struct {
	ID        int64
	MailboxID int64
	CertPEM   string
	KeyPEM    string
	NotAfter  time.Time
	CreatedAt time.Time
}

// MailboxSMIMEContact is another address's public certificate a mailbox owner has
// collected, either added by hand or auto-captured off a verified signature.
type MailboxSMIMEContact struct {
	ID        int64
	MailboxID int64
	Email     string
	CertPEM   string
	CreatedAt time.Time
}

// MailboxPGPIdentity is one of a mailbox's own PGP keypairs — a mailbox may hold
// several. PrivateKeyArmor is stored exactly as the pgp package serializes it,
// already passphrase-protected via OpenPGP's own native key-encryption format (no
// separate ciphertext/nonce/salt columns needed, unlike MailboxSMIMEIdentity).
// Label is a free-text user note distinguishing keys (PGP keys have no expiry).
type MailboxPGPIdentity struct {
	ID              int64
	MailboxID       int64
	Label           string
	Email           string
	Fingerprint     string
	PublicKeyArmor  string
	PrivateKeyArmor string
	CreatedAt       time.Time
}

// MailboxPGPContact is another address's PGP public key a mailbox owner has
// collected — mirrors MailboxSMIMEContact.
type MailboxPGPContact struct {
	ID             int64
	MailboxID      int64
	Email          string
	Label          string
	PublicKeyArmor string
	Fingerprint    string
	CreatedAt      time.Time
}
