/**
 * API Versioning repository — Cosmos DB CRUD for versions and client pins.
 * @module api-versioning/repository
 */

import { getContainer } from '../../lib/cosmos.js';
import type { ApiVersionDoc, ClientVersionPinDoc, VersionStatus } from './types.js';

// =============================================================================
// API Versions
// =============================================================================

export async function createVersion(doc: ApiVersionDoc): Promise<ApiVersionDoc> {
  const container = getContainer('api_versions');
  const { resource } = await container.items.create(doc);
  if (!resource) throw new Error('Failed to create API version');
  return resource as unknown as ApiVersionDoc;
}

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

export async function getVersionByString(
  productId: string,
  version: string
): Promise<ApiVersionDoc | null> {
  const container = getContainer('api_versions');
  const query = 'SELECT * FROM c WHERE c.productId = @productId AND c.version = @version';
  const parameters = [
    { name: '@productId', value: productId },
    { name: '@version', value: version },
  ];
  const { resources } = await container.items
    .query<ApiVersionDoc>({ query, parameters })
    .fetchAll();
  return resources[0] ?? null;
}

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

  const container = getContainer('api_versions');
  const updated: ApiVersionDoc = {
    ...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 API version');
  return resource as unknown as ApiVersionDoc;
}

export async function listVersions(
  productId: string,
  options?: { status?: VersionStatus; limit?: number }
): Promise<{ versions: ApiVersionDoc[]; total: number }> {
  const container = getContainer('api_versions');

  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.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<ApiVersionDoc>({ query, parameters })
    .fetchAll();

  return { versions: resources, total };
}

export async function getActiveVersion(productId: string): Promise<ApiVersionDoc | null> {
  const container = getContainer('api_versions');
  const query =
    'SELECT * FROM c WHERE c.productId = @productId AND c.status = "active" ORDER BY c.releasedAt DESC';
  const parameters = [{ name: '@productId', value: productId }];
  const { resources } = await container.items
    .query<ApiVersionDoc>({ query, parameters })
    .fetchAll();
  return resources[0] ?? null;
}

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

// =============================================================================
// Client Version Pins
// =============================================================================

export async function createPin(doc: ClientVersionPinDoc): Promise<ClientVersionPinDoc> {
  const container = getContainer('api_version_pins');
  const { resource } = await container.items.create(doc);
  if (!resource) throw new Error('Failed to create version pin');
  return resource as unknown as ClientVersionPinDoc;
}

export async function getPin(
  clientId: string,
  productId: string
): Promise<ClientVersionPinDoc | null> {
  const container = getContainer('api_version_pins');
  const query = 'SELECT * FROM c WHERE c.productId = @productId AND c.clientId = @clientId';
  const parameters = [
    { name: '@productId', value: productId },
    { name: '@clientId', value: clientId },
  ];
  const { resources } = await container.items
    .query<ClientVersionPinDoc>({ query, parameters })
    .fetchAll();
  return resources[0] ?? null;
}

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

export async function deletePin(id: string, productId: string): Promise<boolean> {
  const container = getContainer('api_version_pins');
  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 listPins(
  productId: string,
  options?: { version?: string; limit?: number }
): Promise<{ pins: ClientVersionPinDoc[]; total: number }> {
  const container = getContainer('api_version_pins');

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

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

  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<ClientVersionPinDoc>({ query, parameters })
    .fetchAll();

  return { pins: resources, total };
}
