import { randomUUID } from 'node:crypto';
import { getCollection } from '../../lib/datastore.js';
import type {
  WebhookSubscriptionDoc,
  WebhookDeliveryDoc,
  CreateWebhookSubscriptionInput,
  UpdateWebhookSubscriptionInput,
} from './types.js';

function subsCollection() {
  return getCollection<WebhookSubscriptionDoc>('webhook_subscriptions', '/productId');
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function deliveriesCollection(): import('@bytelyst/datastore').DocumentCollection<any> {
  // WebhookDeliveryDoc uses pk instead of productId — doesn't satisfy BaseDocument
  return getCollection('webhook_deliveries', '/pk');
}

// ── Subscription CRUD ───────────────────────────────────────

export async function createSubscription(
  input: CreateWebhookSubscriptionInput,
  secret: string,
  createdBy: string
): Promise<WebhookSubscriptionDoc> {
  const now = new Date().toISOString();
  const doc: WebhookSubscriptionDoc = {
    id: randomUUID(),
    productId: input.productId,
    url: input.url,
    secret,
    events: input.events,
    enabled: true,
    failureCount: 0,
    createdAt: now,
    updatedAt: now,
    createdBy,
  };
  return subsCollection().create(doc);
}

export async function getSubscription(
  id: string,
  productId: string
): Promise<WebhookSubscriptionDoc | undefined> {
  try {
    const doc = await subsCollection().findById(id, productId);
    return doc ?? undefined;
  } catch {
    return undefined;
  }
}

export async function listSubscriptions(productId: string): Promise<WebhookSubscriptionDoc[]> {
  return subsCollection().findMany({
    filter: { productId },
    sort: { createdAt: -1 },
  });
}

export async function updateSubscription(
  id: string,
  productId: string,
  input: UpdateWebhookSubscriptionInput
): Promise<WebhookSubscriptionDoc | undefined> {
  const existing = await getSubscription(id, productId);
  if (!existing) return undefined;

  const updates: Partial<WebhookSubscriptionDoc> = {
    ...(input.url !== undefined && { url: input.url }),
    ...(input.events !== undefined && { events: input.events }),
    ...(input.enabled !== undefined && { enabled: input.enabled }),
    updatedAt: new Date().toISOString(),
  };

  return subsCollection().update(id, productId, updates);
}

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

export async function incrementFailureCount(
  id: string,
  productId: string,
  disable: boolean
): Promise<void> {
  const existing = await getSubscription(id, productId);
  if (!existing) return;

  const now = new Date().toISOString();
  await subsCollection().update(id, productId, {
    failureCount: existing.failureCount + 1,
    ...(disable && { enabled: false }),
    updatedAt: now,
    lastDeliveryAt: now,
  } as Partial<WebhookSubscriptionDoc>);
}

export async function resetFailureCount(id: string, productId: string): Promise<void> {
  const existing = await getSubscription(id, productId);
  if (!existing) return;

  const now = new Date().toISOString();
  await subsCollection().update(id, productId, {
    failureCount: 0,
    lastDeliveryAt: now,
    updatedAt: now,
  } as Partial<WebhookSubscriptionDoc>);
}

// ── Subscription lookup by event ────────────────────────────

export async function findSubscriptionsForEvent(
  productId: string,
  event: string
): Promise<WebhookSubscriptionDoc[]> {
  // Fetch enabled subscriptions and filter for array contains in-memory
  const all = await subsCollection().findMany({
    filter: { productId, enabled: true },
  });
  return all.filter(s => (s.events as string[]).includes(event));
}

// ── Delivery Log ────────────────────────────────────────────

export async function createDelivery(doc: WebhookDeliveryDoc): Promise<WebhookDeliveryDoc> {
  return deliveriesCollection().create(doc);
}

export async function updateDelivery(doc: WebhookDeliveryDoc): Promise<WebhookDeliveryDoc> {
  return deliveriesCollection().upsert(doc);
}

export async function listDeliveries(
  subscriptionId: string,
  options?: { limit?: number }
): Promise<WebhookDeliveryDoc[]> {
  const limit = Math.min(options?.limit ?? 50, 200);
  return deliveriesCollection().findMany({
    filter: { pk: { $startsWith: subscriptionId } },
    sort: { createdAt: -1 },
    limit,
  });
}
