/**
 * Waitlist repository — cloud-agnostic via @bytelyst/datastore.
 *
 * Collection: `waitlist`, partition key: `/email`
 * Cross-partition queries used for admin list/count/stats (acceptable for low-frequency reads).
 */

import type { FilterMap } from '@bytelyst/datastore';
import { getCollection } from '../../lib/datastore.js';
import type { WaitlistEntryDoc, WaitlistStatus, WaitlistSource } from './types.js';

function collection() {
  return getCollection<WaitlistEntryDoc>('waitlist', '/email');
}

// ── Normalize email for case-insensitive dedup ──

export function normalizeEmail(email: string): string {
  return email.trim().toLowerCase();
}

// ── Create ──

export async function create(doc: WaitlistEntryDoc): Promise<WaitlistEntryDoc> {
  return collection().create(doc);
}

// ── Read (single) ──

export async function getById(id: string): Promise<WaitlistEntryDoc | null> {
  // Cross-partition lookup by id
  return collection().findOne({ filter: { id } });
}

export async function getByEmail(
  emailNormalized: string,
  productId: string
): Promise<WaitlistEntryDoc | null> {
  return collection().findOne({
    filter: { emailNormalized, productId },
  });
}

export async function getByUnsubscribeToken(token: string): Promise<WaitlistEntryDoc | null> {
  return collection().findOne({
    filter: { unsubscribeToken: token },
  });
}

// ── List (admin, cross-partition) ──

export interface ListOptions {
  productId?: string;
  status?: WaitlistStatus;
  source?: WaitlistSource;
  q?: string;
  sortBy: string;
  sortOrder: string;
  limit: number;
  offset: number;
}

export async function list(opts: ListOptions): Promise<{
  items: WaitlistEntryDoc[];
  total: number;
}> {
  const filter: FilterMap = {};
  if (opts.productId) filter.productId = opts.productId;
  if (opts.status) filter.status = opts.status;
  if (opts.source) filter.source = opts.source;

  // Allowed sort columns (whitelist)
  const sortCol = ['position', 'priority', 'createdAt'].includes(opts.sortBy)
    ? opts.sortBy
    : 'position';
  const sortDir = opts.sortOrder === 'desc' ? -1 : 1;

  let allDocs = await collection().findMany({
    filter,
    sort: { [sortCol]: sortDir },
  });

  // In-memory text search
  if (opts.q) {
    const q = opts.q.toLowerCase();
    allDocs = allDocs.filter(
      d => d.email?.toLowerCase().includes(q) || d.name?.toLowerCase().includes(q)
    );
  }

  const total = allDocs.length;
  const items = allDocs.slice(opts.offset, opts.offset + opts.limit);

  return { items, total };
}

// ── Count ──

export async function count(productId: string): Promise<number> {
  return collection().count({ productId, status: { $ne: 'unsubscribed' } });
}

// ── Next position ──

export async function getNextPosition(productId: string): Promise<number> {
  // Fetch all docs and find max position in-memory
  const docs = await collection().findMany({
    filter: { productId },
  });
  let maxPos = 0;
  for (const d of docs) {
    if (typeof d.position === 'number' && d.position > maxPos) maxPos = d.position;
  }
  return maxPos + 1;
}

// ── Update ──

export async function update(
  id: string,
  email: string,
  updates: Partial<WaitlistEntryDoc>
): Promise<WaitlistEntryDoc | null> {
  try {
    return await collection().update(id, email, {
      ...updates,
      updatedAt: new Date().toISOString(),
    });
  } catch {
    return null;
  }
}

// ── Unsubscribe ──

export async function unsubscribe(token: string): Promise<WaitlistEntryDoc | null> {
  const entry = await getByUnsubscribeToken(token);
  if (!entry) return null;
  if (entry.status === 'unsubscribed') return entry; // idempotent
  return update(entry.id, entry.email, { status: 'unsubscribed' });
}

// ── Delete ──

export async function remove(id: string, email: string): Promise<boolean> {
  try {
    await collection().delete(id, email);
    return true;
  } catch {
    return false;
  }
}

// ── Batch query by status (for invite flow) ──

export async function getByStatus(
  productId: string,
  status: WaitlistStatus,
  sortBy: 'position' | 'priority',
  limit: number
): Promise<WaitlistEntryDoc[]> {
  const sortDir = sortBy === 'priority' ? -1 : 1;
  return collection().findMany({
    filter: { productId, status },
    sort: { [sortBy]: sortDir },
    limit,
  });
}

// ── Stats (admin analytics) ──

export interface WaitlistStats {
  total: number;
  byStatus: Record<string, number>;
  bySource: Record<string, number>;
  todaySignups: number;
}

export async function stats(productId: string): Promise<WaitlistStats> {
  const docs = await collection().findMany({
    filter: { productId },
  });

  const byStatus: Record<string, number> = {};
  const bySource: Record<string, number> = {};
  const todayStr = new Date().toISOString().slice(0, 10);
  let todaySignups = 0;

  for (const entry of docs) {
    byStatus[entry.status] = (byStatus[entry.status] || 0) + 1;
    bySource[entry.source] = (bySource[entry.source] || 0) + 1;
    if (entry.createdAt.startsWith(todayStr)) todaySignups++;
  }

  return { total: docs.length, byStatus, bySource, todaySignups };
}
