/**
 * CDN Pipeline repository — Cosmos DB CRUD for assets, purge requests, and origin config.
 * @module cdn/repository
 */

import { getContainer } from '../../lib/cosmos.js';
import type {
  CdnAssetDoc,
  CdnPurgeRequestDoc,
  CdnOriginConfigDoc,
  AssetCategory,
} from './types.js';

// =============================================================================
// Assets
// =============================================================================

export async function createAsset(doc: CdnAssetDoc): Promise<CdnAssetDoc> {
  const container = getContainer('cdn_assets');
  const { resource } = await container.items.create(doc);
  if (!resource) throw new Error('Failed to create CDN asset');
  return resource as unknown as CdnAssetDoc;
}

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

export async function listAssets(
  productId: string,
  options?: { category?: AssetCategory; limit?: number; offset?: number }
): Promise<{ assets: CdnAssetDoc[]; total: number }> {
  const container = getContainer('cdn_assets');

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

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

  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;

  if (options?.limit) {
    query += ` OFFSET ${options.offset ?? 0} LIMIT ${options.limit}`;
  }

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

  return { assets: resources, total };
}

export async function deleteAsset(id: string, productId: string): Promise<boolean> {
  const container = getContainer('cdn_assets');
  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 getAssetByHash(
  productId: string,
  contentHash: string
): Promise<CdnAssetDoc | null> {
  const container = getContainer('cdn_assets');
  const query = 'SELECT * FROM c WHERE c.productId = @productId AND c.contentHash = @hash';
  const parameters = [
    { name: '@productId', value: productId },
    { name: '@hash', value: contentHash },
  ];

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

  return resources[0] ?? null;
}

export async function getStorageStats(productId: string): Promise<{
  totalAssets: number;
  totalSizeBytes: number;
  byCategory: Record<string, { count: number; sizeBytes: number }>;
}> {
  const container = getContainer('cdn_assets');
  const query = 'SELECT c.category, c.sizeBytes FROM c WHERE c.productId = @productId';
  const parameters = [{ name: '@productId', value: productId }];

  const { resources } = await container.items
    .query<{ category: string; sizeBytes: number }>({ query, parameters })
    .fetchAll();

  const byCategory: Record<string, { count: number; sizeBytes: number }> = {};
  let totalSizeBytes = 0;

  for (const r of resources) {
    totalSizeBytes += r.sizeBytes;
    if (!byCategory[r.category]) {
      byCategory[r.category] = { count: 0, sizeBytes: 0 };
    }
    byCategory[r.category].count++;
    byCategory[r.category].sizeBytes += r.sizeBytes;
  }

  return { totalAssets: resources.length, totalSizeBytes, byCategory };
}

// =============================================================================
// Purge Requests
// =============================================================================

export async function createPurgeRequest(doc: CdnPurgeRequestDoc): Promise<CdnPurgeRequestDoc> {
  const container = getContainer('cdn_purge_requests');
  const { resource } = await container.items.create(doc);
  if (!resource) throw new Error('Failed to create purge request');
  return resource as unknown as CdnPurgeRequestDoc;
}

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

export async function updatePurgeStatus(
  id: string,
  productId: string,
  status: CdnPurgeRequestDoc['status'],
  purgedCount?: number,
  error?: string
): Promise<CdnPurgeRequestDoc | null> {
  const existing = await getPurgeRequest(id, productId);
  if (!existing) return null;

  const container = getContainer('cdn_purge_requests');
  const updated: CdnPurgeRequestDoc = {
    ...existing,
    status,
    purgedCount: purgedCount ?? existing.purgedCount,
    completedAt: status === 'completed' || status === 'failed' ? new Date().toISOString() : null,
    error: error ?? null,
  };

  const { resource } = await container.items.upsert(updated);
  return resource as unknown as CdnPurgeRequestDoc;
}

export async function listPurgeRequests(
  productId: string,
  limit = 20
): Promise<CdnPurgeRequestDoc[]> {
  const container = getContainer('cdn_purge_requests');
  const safeLimit = Math.min(Math.max(limit, 1), 100);
  const query = `SELECT TOP ${safeLimit} * FROM c WHERE c.productId = @productId ORDER BY c.createdAt DESC`;
  const parameters = [{ name: '@productId', value: productId }];

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

  return resources;
}

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

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

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