#!/bin/bash
# Generate TypeScript API client from OpenAPI spec
#
# Usage:
#   ./scripts/generate-client.sh [SPEC_URL]
#
# Environment:
#   SPEC_URL - OpenAPI spec URL (default: http://localhost:8080/openapi.json)

set -e

SPEC_URL="${1:-${SPEC_URL:-http://localhost:8080/openapi.json}}"
OUTPUT_DIR="packages/api-client/src"

echo "Generating TypeScript client from: $SPEC_URL"

# Ensure output directory exists
mkdir -p "$OUTPUT_DIR"

# Generate TypeScript types from OpenAPI spec
npx openapi-typescript "$SPEC_URL" -o "$OUTPUT_DIR/schema.d.ts"

echo "Generated: $OUTPUT_DIR/schema.d.ts"

# Create client wrapper if it doesn't exist
if [ ! -f "$OUTPUT_DIR/client.ts" ]; then
  cat > "$OUTPUT_DIR/client.ts" << 'EOF'
import type { paths } from './schema';

export type { paths };

/**
 * API Client Configuration
 */
export interface ClientConfig {
  baseUrl: string;
  apiKey?: string;
  bearerToken?: string;
  headers?: Record<string, string>;
  onError?: (error: Error) => void;
}

/**
 * Create a typed API client
 */
export function createClient(config: ClientConfig) {
  const { baseUrl, apiKey, bearerToken, headers = {}, onError } = config;

  async function request<T>(
    method: string,
    path: string,
    options: {
      body?: unknown;
      params?: Record<string, string | number | boolean | undefined>;
      headers?: Record<string, string>;
    } = {}
  ): Promise<T> {
    const url = new URL(path, baseUrl);

    // Add query params
    if (options.params) {
      for (const [key, value] of Object.entries(options.params)) {
        if (value !== undefined) {
          url.searchParams.set(key, String(value));
        }
      }
    }

    // Build headers
    const requestHeaders: Record<string, string> = {
      'Content-Type': 'application/json',
      ...headers,
      ...options.headers,
    };

    if (apiKey) {
      requestHeaders['X-API-Key'] = apiKey;
    }
    if (bearerToken) {
      requestHeaders['Authorization'] = `Bearer ${bearerToken}`;
    }

    const response = await fetch(url.toString(), {
      method,
      headers: requestHeaders,
      body: options.body ? JSON.stringify(options.body) : undefined,
    });

    if (!response.ok) {
      const error = new Error(`API error: ${response.status}`);
      if (onError) {
        onError(error);
      }
      throw error;
    }

    // Handle no-content responses
    if (response.status === 204) {
      return undefined as T;
    }

    return response.json();
  }

  return {
    get: <T>(path: string, params?: Record<string, string | number | boolean | undefined>) =>
      request<T>('GET', path, { params }),
    post: <T>(path: string, body?: unknown) =>
      request<T>('POST', path, { body }),
    put: <T>(path: string, body?: unknown) =>
      request<T>('PUT', path, { body }),
    patch: <T>(path: string, body?: unknown) =>
      request<T>('PATCH', path, { body }),
    delete: <T>(path: string) =>
      request<T>('DELETE', path),
  };
}
EOF
  echo "Created: $OUTPUT_DIR/client.ts"
fi

# Create index if it doesn't exist
if [ ! -f "$OUTPUT_DIR/index.ts" ]; then
  cat > "$OUTPUT_DIR/index.ts" << 'EOF'
export * from './client';
export type { paths, components, operations } from './schema';
EOF
  echo "Created: $OUTPUT_DIR/index.ts"
fi

echo "Done! Client generated in: $OUTPUT_DIR"
