package db

import (
	"crypto/rand"
	"database/sql"
	"encoding/hex"
	"errors"
	"time"
)

// --- Sessions --- (mirrors crud_admin.go's session functions, parallel schema)

func newMailboxSessionToken() string {
	b := make([]byte, 32)
	rand.Read(b)
	return hex.EncodeToString(b)
}

func (d *DB) CreateMailboxSession(mailboxID int64, mfaVerified bool, ttl time.Duration) (string, error) {
	token := newMailboxSessionToken()
	_, err := d.Exec(`INSERT INTO esrv_mailbox_sessions (token, mailbox_id, mfa_verified, expires_at) VALUES (?, ?, ?, ?)`,
		token, mailboxID, mfaVerified, time.Now().Add(ttl))
	if err != nil {
		return "", err
	}
	return token, nil
}

func (d *DB) GetMailboxSession(token string) (*MailboxSession, error) {
	row := d.QueryRow(`SELECT token, mailbox_id, mfa_verified, created_at, expires_at FROM esrv_mailbox_sessions WHERE token = ?`, token)
	var s MailboxSession
	var createdAt, expiresAt string
	if err := row.Scan(&s.Token, &s.MailboxID, &s.MFAVerified, &createdAt, &expiresAt); err != nil {
		if errors.Is(err, sql.ErrNoRows) {
			return nil, nil
		}
		return nil, err
	}
	s.CreatedAt, _ = parseTime(createdAt)
	s.ExpiresAt, _ = parseTime(expiresAt)
	return &s, nil
}

func (d *DB) MarkMailboxSessionMFAVerified(token string) error {
	_, err := d.Exec(`UPDATE esrv_mailbox_sessions SET mfa_verified = 1 WHERE token = ?`, token)
	return err
}

func (d *DB) DeleteMailboxSession(token string) error {
	_, err := d.Exec(`DELETE FROM esrv_mailbox_sessions WHERE token = ?`, token)
	return err
}

// --- WebAuthn credentials --- (mirrors crud_admin.go, parallel schema)

func (d *DB) ListMailboxWebAuthnCredentials(mailboxID int64) ([]MailboxWebAuthnCredential, error) {
	rows, err := d.Query(`SELECT id, mailbox_id, name, credential_id, credential_data, created_at FROM esrv_mailbox_webauthn_credentials WHERE mailbox_id = ? ORDER BY created_at`, mailboxID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var out []MailboxWebAuthnCredential
	for rows.Next() {
		var c MailboxWebAuthnCredential
		var createdAt string
		if err := rows.Scan(&c.ID, &c.MailboxID, &c.Name, &c.CredentialID, &c.CredentialData, &createdAt); err != nil {
			return nil, err
		}
		c.CreatedAt, _ = parseTime(createdAt)
		out = append(out, c)
	}
	return out, rows.Err()
}

func (d *DB) CreateMailboxWebAuthnCredential(mailboxID int64, name, credentialID, credentialData string) error {
	_, err := d.Exec(`INSERT INTO esrv_mailbox_webauthn_credentials (mailbox_id, name, credential_id, credential_data) VALUES (?, ?, ?, ?)`,
		mailboxID, name, credentialID, credentialData)
	return err
}

func (d *DB) DeleteMailboxWebAuthnCredential(id, mailboxID int64) error {
	_, err := d.Exec(`DELETE FROM esrv_mailbox_webauthn_credentials WHERE id = ? AND mailbox_id = ?`, id, mailboxID)
	return err
}

func (d *DB) CountMailboxWebAuthnCredentials(mailboxID int64) (int, error) {
	var n int
	err := d.QueryRow(`SELECT COUNT(*) FROM esrv_mailbox_webauthn_credentials WHERE mailbox_id = ?`, mailboxID).Scan(&n)
	return n, err
}
