/**
 * Usage/budget proxy routes — forward queries to platform-service /usage endpoints.
 *
 * Lets the Tauri desktop check AI budget consumption and plan limits
 * via cowork-service, which proxies to platform-service.
 */

import type { FastifyInstance } from 'fastify';
import { config } from '../../lib/config.js';
import { PRODUCT_ID } from '../../lib/product-config.js';
import { getUserId } from '../../lib/request-context.js';
import {
  BudgetPolicyPayloadSchema,
  CheckLimitsSchema,
  UsageSummaryQuerySchema,
  type BudgetPolicyPayload,
} from './types.js';

type PlatformBudgetPolicy = {
  id: string;
  period: 'daily' | 'monthly';
  budgetUsd: number;
  modelAllowlist?: string[];
  scopeType: string;
  scopeId: string;
  status?: string;
};

function buildProxyHeaders(
  req: import('fastify').FastifyRequest,
  contentType = false
): Record<string, string> {
  const headers: Record<string, string> = {
    'x-product-id': PRODUCT_ID,
    'x-request-id': req.id,
  };
  if (contentType) headers['Content-Type'] = 'application/json';
  const auth = req.headers.authorization;
  if (typeof auth === 'string') headers.authorization = auth;
  return headers;
}

async function listBudgetPolicies(
  platformUrl: string,
  req: import('fastify').FastifyRequest
): Promise<PlatformBudgetPolicy[]> {
  const params = new URLSearchParams({
    scopeType: 'product',
    scopeId: PRODUCT_ID,
    status: 'active',
    limit: '20',
  });
  const res = await fetch(`${platformUrl}/ai-budgets/policies?${params.toString()}`, {
    headers: buildProxyHeaders(req),
  });
  if (!res.ok) {
    const body = (await res.json().catch(() => null)) as { error?: string } | null;
    const error = new Error(body?.error ?? `Platform returned ${res.status}`);
    (error as Error & { statusCode?: number }).statusCode = res.status;
    throw error;
  }
  return (await res.json()) as PlatformBudgetPolicy[];
}

async function upsertPolicy(
  platformUrl: string,
  req: import('fastify').FastifyRequest,
  existing: PlatformBudgetPolicy | undefined,
  period: 'daily' | 'monthly',
  payload: BudgetPolicyPayload
): Promise<PlatformBudgetPolicy> {
  const budgetUsd = period === 'daily' ? payload.dailyBudgetUsd : payload.monthlyBudgetUsd;
  const body = {
    scopeType: 'product',
    scopeId: PRODUCT_ID,
    name: `Claw Cowork ${period === 'daily' ? 'Daily' : 'Monthly'} Budget`,
    period,
    budgetUsd,
    softThreshold: 0.8,
    hardThreshold: 1,
    modelAllowlist: payload.modelAllowlist,
  };

  const targetUrl = existing
    ? `${platformUrl}/ai-budgets/policies/${encodeURIComponent(existing.id)}`
    : `${platformUrl}/ai-budgets/policies`;
  const method = existing ? 'PATCH' : 'POST';

  const res = await fetch(targetUrl, {
    method,
    headers: buildProxyHeaders(req, true),
    body: JSON.stringify(body),
  });
  if (!res.ok) {
    const body = (await res.json().catch(() => null)) as { error?: string } | null;
    const error = new Error(body?.error ?? `Platform returned ${res.status}`);
    (error as Error & { statusCode?: number }).statusCode = res.status;
    throw error;
  }
  return (await res.json()) as PlatformBudgetPolicy;
}

export async function usageRoutes(app: FastifyInstance) {
  const platformUrl = config.PLATFORM_SERVICE_URL;

  // GET /api/usage/summary — proxy to platform-service GET /usage/summary
  app.get('/api/usage/summary', async (req, reply) => {
    const parsed = UsageSummaryQuerySchema.safeParse(req.query);
    if (!parsed.success) {
      reply.code(400);
      return { error: 'Invalid query', details: parsed.error.issues };
    }

    const userId = getUserId(req);
    const { days } = parsed.data;

    try {
      const res = await fetch(
        `${platformUrl}/usage/summary?userId=${encodeURIComponent(userId)}&days=${days}`,
        {
          headers: buildProxyHeaders(req),
        }
      );
      if (!res.ok) {
        reply.code(res.status);
        return { error: `Platform returned ${res.status}` };
      }
      return res.json();
    } catch (err) {
      req.log.warn({ err }, 'Failed to proxy usage summary to platform-service');
      reply.code(502);
      return { error: 'Platform-service unavailable' };
    }
  });

  // POST /api/usage/check-limits — proxy to platform-service POST /usage/check-limits
  app.post('/api/usage/check-limits', async (req, reply) => {
    const parsed = CheckLimitsSchema.safeParse(req.body);
    if (!parsed.success) {
      reply.code(400);
      return { error: 'Invalid body', details: parsed.error.issues };
    }

    const userId = getUserId(req);
    const { plan } = parsed.data;

    try {
      const res = await fetch(`${platformUrl}/usage/check-limits`, {
        method: 'POST',
        headers: buildProxyHeaders(req, true),
        body: JSON.stringify({ userId, plan }),
      });
      if (!res.ok) {
        reply.code(res.status);
        return { error: `Platform returned ${res.status}` };
      }
      return res.json();
    } catch (err) {
      req.log.warn({ err }, 'Failed to proxy limit check to platform-service');
      reply.code(502);
      return { error: 'Platform-service unavailable' };
    }
  });

  app.get('/api/usage/budget-policy', async (req, reply) => {
    try {
      const policies = await listBudgetPolicies(platformUrl, req);
      const daily = policies.find(policy => policy.period === 'daily');
      const monthly = policies.find(policy => policy.period === 'monthly');

      return {
        dailyBudgetUsd: daily?.budgetUsd ?? null,
        monthlyBudgetUsd: monthly?.budgetUsd ?? null,
        modelAllowlist: monthly?.modelAllowlist ?? daily?.modelAllowlist ?? [],
        policies,
      };
    } catch (err) {
      req.log.warn({ err }, 'Failed to load budget policy from platform-service');
      const statusCode =
        err instanceof Error && 'statusCode' in err && typeof err.statusCode === 'number'
          ? err.statusCode
          : 502;
      reply.code(statusCode);
      return {
        error: err instanceof Error ? err.message : 'Platform-service unavailable',
      };
    }
  });

  app.put('/api/usage/budget-policy', async (req, reply) => {
    const parsed = BudgetPolicyPayloadSchema.safeParse(req.body);
    if (!parsed.success) {
      reply.code(400);
      return { error: 'Invalid body', details: parsed.error.issues };
    }

    try {
      const existing = await listBudgetPolicies(platformUrl, req);
      const daily = await upsertPolicy(
        platformUrl,
        req,
        existing.find(policy => policy.period === 'daily'),
        'daily',
        parsed.data
      );
      const monthly = await upsertPolicy(
        platformUrl,
        req,
        existing.find(policy => policy.period === 'monthly'),
        'monthly',
        parsed.data
      );

      return {
        dailyBudgetUsd: daily.budgetUsd,
        monthlyBudgetUsd: monthly.budgetUsd,
        modelAllowlist: monthly.modelAllowlist ?? daily.modelAllowlist ?? [],
        policies: [daily, monthly],
      };
    } catch (err) {
      req.log.warn({ err }, 'Failed to save budget policy to platform-service');
      const statusCode =
        err instanceof Error && 'statusCode' in err && typeof err.statusCode === 'number'
          ? err.statusCode
          : 502;
      reply.code(statusCode);
      return {
        error: err instanceof Error ? err.message : 'Platform-service unavailable',
      };
    }
  });
}
