/**
 * Data Retention repository — Cosmos DB CRUD for policies and jobs.
 * @module retention/repository
 */

import { getContainer } from '../../lib/cosmos.js';
import type { RetentionPolicyDoc, RetentionJobDoc, RetentionJobStatus } from './types.js';

// =============================================================================
// Retention Policies
// =============================================================================

export async function createPolicy(doc: RetentionPolicyDoc): Promise<RetentionPolicyDoc> {
  const container = getContainer('retention_policies');
  const { resource } = await container.items.create(doc);
  if (!resource) throw new Error('Failed to create retention policy');
  return resource as unknown as RetentionPolicyDoc;
}

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

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

  const container = getContainer('retention_policies');
  const updated: RetentionPolicyDoc = {
    ...existing,
    ...updates,
    id: existing.id,
    productId: existing.productId,
    updatedAt: new Date().toISOString(),
  };

  const { resource } = await container.items.upsert(updated);
  if (!resource) throw new Error('Failed to update retention policy');
  return resource as unknown as RetentionPolicyDoc;
}

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

export async function listPolicies(
  productId: string,
  options?: { isEnabled?: boolean; limit?: number }
): Promise<{ policies: RetentionPolicyDoc[]; total: number }> {
  const container = getContainer('retention_policies');

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

  if (options?.isEnabled !== undefined) {
    query += ' AND c.isEnabled = @isEnabled';
    parameters.push({ name: '@isEnabled', value: options.isEnabled as unknown as string });
  }

  query += ' ORDER BY c.createdAt 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 ?? 50, 1), 200);
  query += ` OFFSET 0 LIMIT ${safeLimit}`;

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

  return { policies: resources, total };
}

export async function getEnabledPolicies(productId: string): Promise<RetentionPolicyDoc[]> {
  const container = getContainer('retention_policies');
  const query = 'SELECT * FROM c WHERE c.productId = @productId AND c.isEnabled = true';
  const parameters = [{ name: '@productId', value: productId }];
  const { resources } = await container.items
    .query<RetentionPolicyDoc>({ query, parameters })
    .fetchAll();
  return resources;
}

// =============================================================================
// Retention Jobs (audit trail)
// =============================================================================

export async function createJob(doc: RetentionJobDoc): Promise<RetentionJobDoc> {
  const container = getContainer('retention_jobs');
  const { resource } = await container.items.create(doc);
  if (!resource) throw new Error('Failed to create retention job');
  return resource as unknown as RetentionJobDoc;
}

export async function updateJob(
  id: string,
  productId: string,
  updates: Partial<RetentionJobDoc>
): Promise<RetentionJobDoc | null> {
  const container = getContainer('retention_jobs');
  try {
    const { resource: existing } = await container.item(id, productId).read();
    if (!existing) return null;
    const updated = { ...existing, ...updates };
    const { resource } = await container.items.upsert(updated);
    return resource as unknown as RetentionJobDoc;
  } catch (err) {
    if ((err as { code?: number }).code === 404) return null;
    throw err;
  }
}

export async function listJobs(
  productId: string,
  options?: { policyId?: string; status?: RetentionJobStatus; limit?: number }
): Promise<{ jobs: RetentionJobDoc[]; total: number }> {
  const container = getContainer('retention_jobs');

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

  if (options?.policyId) {
    query += ' AND c.policyId = @policyId';
    parameters.push({ name: '@policyId', value: options.policyId });
  }
  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<RetentionJobDoc>({ query, parameters })
    .fetchAll();

  return { jobs: resources, total };
}

export async function getRetentionStats(productId: string): Promise<{
  totalPolicies: number;
  enabledPolicies: number;
  totalJobsRun: number;
  totalPurgedDocuments: number;
}> {
  const container = getContainer('retention_policies');
  const policyQuery = 'SELECT c.isEnabled FROM c WHERE c.productId = @productId';
  const parameters = [{ name: '@productId', value: productId }];

  const { resources: policies } = await container.items
    .query<{ isEnabled: boolean }>({ query: policyQuery, parameters })
    .fetchAll();

  const totalPolicies = policies.length;
  const enabledPolicies = policies.filter(p => p.isEnabled).length;

  const jobContainer = getContainer('retention_jobs');
  const jobQuery =
    'SELECT c.purgedCount FROM c WHERE c.productId = @productId AND c.status = "completed"';
  const { resources: jobs } = await jobContainer.items
    .query<{ purgedCount: number }>({ query: jobQuery, parameters })
    .fetchAll();

  const totalJobsRun = jobs.length;
  const totalPurgedDocuments = jobs.reduce((sum, j) => sum + j.purgedCount, 0);

  return { totalPolicies, enabledPolicies, totalJobsRun, totalPurgedDocuments };
}
