import { NotFoundError } from '../../lib/errors.js';
import { getCollection } from '../../lib/datastore.js';
import type {
  BudgetAlertDoc,
  BudgetPolicyDoc,
  BudgetRolloverDoc,
  BudgetSpendEntryDoc,
  ListBudgetAlertsQuery,
  ListBudgetPoliciesQuery,
} from './types.js';

function policyCollection() {
  return getCollection<BudgetPolicyDoc>('ai_budget_policies', '/productId');
}

function spendCollection() {
  return getCollection<BudgetSpendEntryDoc>('ai_budget_spend_entries', '/productId');
}

function alertCollection() {
  return getCollection<BudgetAlertDoc>('ai_budget_alerts', '/productId');
}

export async function createPolicy(doc: BudgetPolicyDoc): Promise<BudgetPolicyDoc> {
  return policyCollection().create(doc);
}

export async function listPolicies(
  productId: string,
  query: ListBudgetPoliciesQuery
): Promise<BudgetPolicyDoc[]> {
  return policyCollection().findMany({
    filter: {
      productId,
      ...(query.scopeType ? { scopeType: query.scopeType } : {}),
      ...(query.scopeId ? { scopeId: query.scopeId } : {}),
      ...(query.status ? { status: query.status } : {}),
    },
    sort: { createdAt: -1 },
    limit: query.limit,
  });
}

export async function getPolicy(id: string, productId: string): Promise<BudgetPolicyDoc> {
  const policy = await policyCollection().findById(id, productId);
  if (!policy) throw new NotFoundError(`Budget policy '${id}' not found`);
  return policy;
}

export async function updatePolicy(
  id: string,
  productId: string,
  updates: Partial<BudgetPolicyDoc>
): Promise<BudgetPolicyDoc> {
  const updated = await policyCollection().update(id, productId, {
    ...updates,
    updatedAt: new Date().toISOString(),
  });
  if (!updated) throw new NotFoundError(`Budget policy '${id}' not found`);
  return updated;
}

export async function createSpendEntry(doc: BudgetSpendEntryDoc): Promise<BudgetSpendEntryDoc> {
  return spendCollection().create(doc);
}

export async function listSpendEntries(
  productId: string,
  filter: { policyId?: string; scopeType?: string; scopeId?: string; since?: string } = {}
): Promise<BudgetSpendEntryDoc[]> {
  return spendCollection().findMany({
    filter: {
      productId,
      ...(filter.policyId ? { policyId: filter.policyId } : {}),
      ...(filter.scopeType ? { scopeType: filter.scopeType } : {}),
      ...(filter.scopeId ? { scopeId: filter.scopeId } : {}),
      ...(filter.since ? { recordedAt: { $gte: filter.since } } : {}),
    } as import('@bytelyst/datastore').FilterMap,
    sort: { recordedAt: -1 },
    limit: 1000,
  });
}

export async function createAlerts(docs: BudgetAlertDoc[]): Promise<BudgetAlertDoc[]> {
  const writes = docs.map(doc => alertCollection().create(doc));
  return Promise.all(writes);
}

export async function listAlerts(
  productId: string,
  query: ListBudgetAlertsQuery
): Promise<BudgetAlertDoc[]> {
  return alertCollection().findMany({
    filter: {
      productId,
      ...(query.severity ? { severity: query.severity } : {}),
    },
    sort: { createdAt: -1 },
    limit: query.limit,
  });
}

// ── Budget Rollover ─────────────────────────────────────────

function rolloverCollection() {
  return getCollection<BudgetRolloverDoc>('ai_budget_rollovers', '/productId');
}

export async function createRollover(doc: BudgetRolloverDoc): Promise<BudgetRolloverDoc> {
  return rolloverCollection().create(doc);
}

export async function listRollovers(
  productId: string,
  policyId: string
): Promise<BudgetRolloverDoc[]> {
  return rolloverCollection().findMany({
    filter: { productId, policyId },
    sort: { createdAt: -1 },
    limit: 50,
  });
}

// ── Cost Dashboard ──────────────────────────────────────────

export async function listAllSpendEntries(
  productId: string,
  options: {
    scopeType?: string;
    scopeId?: string;
    since?: string;
    until?: string;
    limit?: number;
  } = {}
): Promise<BudgetSpendEntryDoc[]> {
  const entries = await spendCollection().findMany({
    filter: {
      productId,
      ...(options.scopeType ? { scopeType: options.scopeType } : {}),
      ...(options.scopeId ? { scopeId: options.scopeId } : {}),
    },
    sort: { recordedAt: -1 },
    limit: options.limit ?? 500,
  });

  // Filter by time range in-memory
  return entries.filter(e => {
    if (options.since && e.recordedAt < options.since) return false;
    if (options.until && e.recordedAt > options.until) return false;
    return true;
  });
}
