/**
 * Shared smart-route matcher for admin user search.
 *
 * Encrypted phone/email are searched by blind index (HMAC exact match) using the
 * EXACT write-time string form. Substring search on ciphertext is impossible, so
 * phone/email are exact-match only by construction.
 *
 * Write-time derivations (must mirror exactly):
 *   phoneIndex = blindIndex(<E.164 with '+'>, PII_KEY)    // firebase-verify.ts:257
 *   emailIndex = blindIndex(email.toLowerCase(), PII_KEY) // register.ts:71,75 — NO canonicalize
 */
import { eq, ilike, or, sql, type SQL } from 'drizzle-orm';
import { users, vendors, vendorTranslations } from '@/server/db/schema.js';
import { VENDOR_DEFAULT_LOCALE } from '@/server/db/queries/vendors.js';
import { blindIndex } from '@/server/db/crypto.js';

export type UserSearchKind = 'email' | 'phone' | 'uuid' | 'name';

/** IL-only E.164 normalization. Yields '+972…' to match Firebase-issued E.164. */
export function toE164IL(raw: string): string {
  const digits = raw.replace(/\D/g, '');
  if (digits.startsWith('972')) return '+' + digits;
  if (digits.startsWith('0')) return '+972' + digits.slice(1);
  return '+972' + digits;
}

/**
 * STRICT — full RFC-shape uuid or bare 32-hex only. No partial/prefix form:
 * eq(users.id, q) is exact-match (partial never matches) and Postgres throws
 * 'invalid input syntax for type uuid' on malformed input -> 500.
 */
export function isUuid(q: string): boolean {
  const t = q.trim();
  return (
    /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(t) ||
    /^[0-9a-f]{32}$/i.test(t)
  );
}

export function classifyUserQuery(q: string): UserSearchKind {
  const t = q.trim();
  if (t.includes('@')) return 'email';
  const digits = t.replace(/\D/g, '');
  if (!/[a-z]/i.test(t) && digits.length >= 7 && digits.length <= 15) return 'phone';
  if (isUuid(t)) return 'uuid';
  return 'name';
}

/** EXISTS subquery: user owns a vendor whose default-locale display name ILIKEs term. */
function vendorNameMatch(term: string): SQL {
  return sql`EXISTS (SELECT 1 FROM ${vendorTranslations} vt2 INNER JOIN ${vendors} v2 ON v2.id = vt2.vendor_id AND v2.owner_user_id = ${sql.raw('"users"."id"')} WHERE vt2.locale = ${VENDOR_DEFAULT_LOCALE} AND vt2.display_name ILIKE ${`%${term}%`})`;
}

/**
 * Build the COMPLETE Drizzle WHERE condition for a user search.
 * One condition so every caller applies identical logic (the name OR can't drift).
 * Caller must guarantee q is trimmed-non-empty.
 */
export async function buildUserSearchCondition(q: string, piiKey: string): Promise<SQL> {
  const t = q.trim();
  const kind = classifyUserQuery(t);
  switch (kind) {
    case 'email': {
      const idx = await blindIndex(t.toLowerCase(), piiKey); // mirror register.ts:71
      return eq(users.emailIndex, idx);
    }
    case 'phone': {
      const idx = await blindIndex(toE164IL(t), piiKey); // mirror firebase-verify.ts:257
      return eq(users.phoneIndex, idx);
    }
    case 'uuid':
      return eq(users.id, t);
    case 'name':
      return or(ilike(users.displayName, `%${t}%`), vendorNameMatch(t)) as SQL;
  }
}
