package migration

import (
	"context"
	"strings"

	"github.com/jackc/pgx/v5/pgxpool"
)

// HasPendingMigrationInvite reports whether an unclaimed invite exists for the email.
func HasPendingMigrationInvite(ctx context.Context, db *pgxpool.Pool, email string) (bool, error) {
	if db == nil {
		return false, nil
	}
	email = normalizeInviteEmail(email)
	if email == "" {
		return false, nil
	}
	var exists bool
	err := db.QueryRow(ctx, `
		SELECT EXISTS(
			SELECT 1 FROM migration_invites
			WHERE status = 'invited' AND lower(email) = lower($1)
		)
	`, email).Scan(&exists)
	return exists, err
}

// ProvisionAudit counts user-linked provision artifacts for test verification.
type ProvisionAudit struct {
	Users        int
	Mailboxes    int
	MailAccounts int
	NCPrincipals int
}

// AuditProvisionByEmail counts rows tied to an email across users, mailboxes, mail accounts, and Nextcloud credentials.
func AuditProvisionByEmail(ctx context.Context, db *pgxpool.Pool, email string) (ProvisionAudit, error) {
	var audit ProvisionAudit
	if db == nil {
		return audit, nil
	}
	email = strings.ToLower(strings.TrimSpace(email))
	if email == "" {
		return audit, nil
	}

	if err := db.QueryRow(ctx, `
		SELECT COUNT(*) FROM users WHERE lower(email) = $1
	`, email).Scan(&audit.Users); err != nil {
		return audit, err
	}
	if err := db.QueryRow(ctx, `
		SELECT COUNT(*)
		FROM mailboxes mb
		JOIN mail_domains md ON md.id = mb.domain_id
		WHERE lower(mb.local_part || '@' || md.name) = $1
	`, email).Scan(&audit.Mailboxes); err != nil {
		return audit, err
	}
	if err := db.QueryRow(ctx, `
		SELECT COUNT(*) FROM mail_accounts WHERE lower(email) = $1
	`, email).Scan(&audit.MailAccounts); err != nil {
		return audit, err
	}
	if err := db.QueryRow(ctx, `
		SELECT COUNT(*) FROM nextcloud_dav_credentials WHERE nc_user_id = $1
	`, email).Scan(&audit.NCPrincipals); err != nil {
		return audit, err
	}
	return audit, nil
}

// LinkHostedMailboxByEmail attaches orphan mailboxes/mail_accounts (e.g. from claim-before-enroll) to a user.
func LinkHostedMailboxByEmail(ctx context.Context, db *pgxpool.Pool, userID, email string) error {
	email = strings.ToLower(strings.TrimSpace(email))
	if email == "" {
		return nil
	}
	_, err := db.Exec(ctx, `
		UPDATE mailboxes SET user_id = $1::uuid, updated_at = NOW()
		WHERE user_id IS NULL AND lower(local_part || '@' || (SELECT name FROM mail_domains d WHERE d.id = mailboxes.domain_id)) = $2
	`, userID, email)
	if err != nil {
		return err
	}
	_, err = db.Exec(ctx, `
		UPDATE mail_accounts ma SET user_id = $1::uuid, updated_at = NOW()
		FROM mailboxes mb
		JOIN mail_domains md ON md.id = mb.domain_id
		WHERE mb.mail_account_id = ma.id
		  AND ma.user_id IS NULL
		  AND mb.user_id = $1::uuid
		  AND lower(mb.local_part || '@' || md.name) = $2
	`, userID, email)
	return err
}
