/**
 * Backup/Restore repository — Cosmos DB CRUD for backups, restores, and config.
 * @module backups/repository
 */

import { getContainer } from '../../lib/cosmos.js';
import type { BackupDoc, RestoreDoc, BackupConfigDoc, BackupStatus } from './types.js';

// =============================================================================
// Backups
// =============================================================================

export async function createBackup(doc: BackupDoc): Promise<BackupDoc> {
  const container = getContainer('backups');
  const { resource } = await container.items.create(doc);
  if (!resource) throw new Error('Failed to create backup');
  return resource as unknown as BackupDoc;
}

export async function getBackup(id: string, productId: string): Promise<BackupDoc | null> {
  const container = getContainer('backups');
  try {
    const { resource } = await container.item(id, productId).read();
    return resource as unknown as BackupDoc | null;
  } catch (err) {
    if ((err as { code?: number }).code === 404) return null;
    throw err;
  }
}

export async function updateBackup(
  id: string,
  productId: string,
  updates: Partial<BackupDoc>
): Promise<BackupDoc | null> {
  const existing = await getBackup(id, productId);
  if (!existing) return null;

  const container = getContainer('backups');
  const updated = { ...existing, ...updates, id: existing.id, productId: existing.productId };
  const { resource } = await container.items.upsert(updated);
  if (!resource) throw new Error('Failed to update backup');
  return resource as unknown as BackupDoc;
}

export async function listBackups(
  productId: string,
  options?: { status?: BackupStatus; limit?: number }
): Promise<{ backups: BackupDoc[]; total: number }> {
  const container = getContainer('backups');

  let query = 'SELECT * FROM c WHERE c.productId = @productId';
  const parameters = [{ name: '@productId', value: productId }];

  if (options?.status) {
    query += ' AND c.status = @status';
    parameters.push({ name: '@status', value: options.status });
  }

  query += ' ORDER BY c.startedAt DESC';

  const countQuery = query.replace('SELECT *', 'SELECT VALUE COUNT(1)');
  const { resources: countResult } = await container.items
    .query<number>({ query: countQuery, parameters })
    .fetchAll();
  const total = countResult[0] ?? 0;

  const safeLimit = Math.min(Math.max(options?.limit ?? 20, 1), 100);
  query += ` OFFSET 0 LIMIT ${safeLimit}`;

  const { resources } = await container.items.query<BackupDoc>({ query, parameters }).fetchAll();

  return { backups: resources, total };
}

export async function deleteBackup(id: string, productId: string): Promise<boolean> {
  const container = getContainer('backups');
  try {
    await container.item(id, productId).delete();
    return true;
  } catch (err) {
    if ((err as { code?: number }).code === 404) return false;
    throw err;
  }
}

// =============================================================================
// Restores
// =============================================================================

export async function createRestore(doc: RestoreDoc): Promise<RestoreDoc> {
  const container = getContainer('restores');
  const { resource } = await container.items.create(doc);
  if (!resource) throw new Error('Failed to create restore');
  return resource as unknown as RestoreDoc;
}

export async function getRestore(id: string, productId: string): Promise<RestoreDoc | null> {
  const container = getContainer('restores');
  try {
    const { resource } = await container.item(id, productId).read();
    return resource as unknown as RestoreDoc | null;
  } catch (err) {
    if ((err as { code?: number }).code === 404) return null;
    throw err;
  }
}

export async function updateRestore(
  id: string,
  productId: string,
  updates: Partial<RestoreDoc>
): Promise<RestoreDoc | null> {
  const existing = await getRestore(id, productId);
  if (!existing) return null;

  const container = getContainer('restores');
  const updated = { ...existing, ...updates, id: existing.id, productId: existing.productId };
  const { resource } = await container.items.upsert(updated);
  if (!resource) throw new Error('Failed to update restore');
  return resource as unknown as RestoreDoc;
}

export async function listRestores(
  productId: string,
  options?: { backupId?: string; limit?: number }
): Promise<{ restores: RestoreDoc[]; total: number }> {
  const container = getContainer('restores');

  let query = 'SELECT * FROM c WHERE c.productId = @productId';
  const parameters = [{ name: '@productId', value: productId }];

  if (options?.backupId) {
    query += ' AND c.backupId = @backupId';
    parameters.push({ name: '@backupId', value: options.backupId });
  }

  query += ' ORDER BY c.startedAt DESC';

  const countQuery = query.replace('SELECT *', 'SELECT VALUE COUNT(1)');
  const { resources: countResult } = await container.items
    .query<number>({ query: countQuery, parameters })
    .fetchAll();
  const total = countResult[0] ?? 0;

  const safeLimit = Math.min(Math.max(options?.limit ?? 20, 1), 100);
  query += ` OFFSET 0 LIMIT ${safeLimit}`;

  const { resources } = await container.items.query<RestoreDoc>({ query, parameters }).fetchAll();

  return { restores: resources, total };
}

// =============================================================================
// Backup Config (singleton per product)
// =============================================================================

export async function getConfig(productId: string): Promise<BackupConfigDoc | null> {
  const container = getContainer('backup_configs');
  try {
    const { resource } = await container.item(productId, productId).read();
    return resource as unknown as BackupConfigDoc | null;
  } catch (err) {
    if ((err as { code?: number }).code === 404) return null;
    throw err;
  }
}

export async function upsertConfig(doc: BackupConfigDoc): Promise<BackupConfigDoc> {
  const container = getContainer('backup_configs');
  const { resource } = await container.items.upsert(doc);
  if (!resource) throw new Error('Failed to upsert backup config');
  return resource as unknown as BackupConfigDoc;
}
