package db

import "strings"

func (d *DB) ListAllowBlock(mailboxID int64) ([]MailboxAllowBlockEntry, error) {
	rows, err := d.Query(`SELECT id, mailbox_id, list_type, pattern, created_at
		FROM esrv_mailbox_allowblock WHERE mailbox_id = ? ORDER BY list_type, pattern`, mailboxID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var out []MailboxAllowBlockEntry
	for rows.Next() {
		var e MailboxAllowBlockEntry
		var createdAt string
		if err := rows.Scan(&e.ID, &e.MailboxID, &e.ListType, &e.Pattern, &createdAt); err != nil {
			return nil, err
		}
		e.CreatedAt, _ = parseTime(createdAt)
		out = append(out, e)
	}
	return out, rows.Err()
}

func (d *DB) AddAllowBlockEntry(mailboxID int64, listType, pattern string) (int64, error) {
	res, err := d.Exec(`INSERT OR IGNORE INTO esrv_mailbox_allowblock (mailbox_id, list_type, pattern) VALUES (?, ?, ?)`,
		mailboxID, listType, strings.ToLower(pattern))
	if err != nil {
		return 0, err
	}
	return res.LastInsertId()
}

// RemoveAllowBlockEntry deletes an entry, scoped to mailboxID (mirrors RemoveAppPassword/RemoveAlias).
func (d *DB) RemoveAllowBlockEntry(id, mailboxID int64) error {
	_, err := d.Exec(`DELETE FROM esrv_mailbox_allowblock WHERE id = ? AND mailbox_id = ?`, id, mailboxID)
	return err
}

func (d *DB) IsBlocked(mailboxID int64, senderAddr string) (bool, error) {
	return matchesAllowBlock(d, mailboxID, "block", senderAddr)
}

func (d *DB) IsAllowed(mailboxID int64, senderAddr string) (bool, error) {
	return matchesAllowBlock(d, mailboxID, "allow", senderAddr)
}

// IsJunked reports whether senderAddr matches the mailbox owner's own self-service
// Blocklist ('junk' entries — see esrv_mailbox_allowblock's schema comment for how
// this differs from admin's IsBlocked).
func (d *DB) IsJunked(mailboxID int64, senderAddr string) (bool, error) {
	return matchesAllowBlock(d, mailboxID, "junk", senderAddr)
}

// matchesAllowBlock checks senderAddr against every pattern of listType for mailboxID
// — an exact address match, or a "@domain.com" wildcard matching senderAddr's domain.
func matchesAllowBlock(d *DB, mailboxID int64, listType, senderAddr string) (bool, error) {
	senderAddr = strings.ToLower(senderAddr)
	domain := domainPart(senderAddr)
	rows, err := d.Query(`SELECT pattern FROM esrv_mailbox_allowblock WHERE mailbox_id = ? AND list_type = ?`, mailboxID, listType)
	if err != nil {
		return false, err
	}
	defer rows.Close()
	for rows.Next() {
		var pattern string
		if err := rows.Scan(&pattern); err != nil {
			return false, err
		}
		if strings.HasPrefix(pattern, "@") {
			if pattern[1:] == domain {
				return true, nil
			}
		} else if pattern == senderAddr {
			return true, nil
		}
	}
	return false, rows.Err()
}
