/**
 * Diagnostics Client Library
 * Admin dashboard client for debug sessions, traces, and logs
 */

import { createApiClient } from '@bytelyst/api-client';
import type { ApiClient } from '@bytelyst/api-client';

// =============================================================================
// Types
// =============================================================================

export interface DebugSession {
  id: string;
  productId: string;
  targetUserId?: string;
  targetAnonymousId?: string;
  targetDeviceId?: string;
  targetSessionId?: string;
  status: 'pending' | 'active' | 'paused' | 'completed' | 'cancelled';
  collectionLevel: 'standard' | 'debug' | 'trace';
  captureLogs: boolean;
  captureNetwork: boolean;
  captureScreenshots: boolean;
  screenshotOnError: boolean;
  maxDurationMinutes: number;
  createdAt: string;
  updatedAt: string;
  startedAt?: string;
  endedAt?: string;
  expiresAt: string;
  logCount: number;
  traceCount: number;
  screenshotCount: number;
  createdBy: string;
  updatedBy?: string;
  userConsent?: {
    consentedAt: string;
    consentMethod: 'prompt' | 'pre_consent' | 'auto';
  };
}

export interface CreateSessionRequest {
  targetUserId?: string;
  targetAnonymousId?: string;
  targetDeviceId?: string;
  targetSessionId?: string;
  collectionLevel: 'standard' | 'debug' | 'trace';
  captureLogs?: boolean;
  captureNetwork?: boolean;
  captureScreenshots?: boolean;
  screenshotOnError?: boolean;
  maxDurationMinutes?: number;
}

export interface UpdateSessionRequest {
  status?: 'active' | 'paused' | 'completed' | 'cancelled';
  collectionLevel?: 'standard' | 'debug' | 'trace';
  captureLogs?: boolean;
  captureNetwork?: boolean;
  captureScreenshots?: boolean;
  screenshotOnError?: boolean;
  maxDurationMinutes?: number;
}

export interface QuerySessionsOptions {
  productId: string;
  status?: string;
  targetUserId?: string;
  targetDeviceId?: string;
  startDate?: string;
  endDate?: string;
  limit?: number;
  offset?: number;
}

export interface QuerySessionsResult {
  sessions: DebugSession[];
  total: number;
  limit: number;
  offset: number;
}

export interface TraceSpan {
  id: string;
  sessionId: string;
  productId: string;
  traceId: string;
  parentId?: string;
  spanId: string;
  name: string;
  kind?: 'internal' | 'server' | 'client' | 'producer' | 'consumer';
  startTime: string;
  endTime?: string;
  durationMs?: number;
  attributes: Record<string, unknown>;
  status: 'ok' | 'error' | 'unset';
  statusMessage?: string;
  events?: Array<{
    name: string;
    timestamp: string;
    attributes?: Record<string, unknown>;
  }>;
}

export interface LogEntry {
  id: string;
  sessionId: string;
  productId: string;
  level: 'debug' | 'info' | 'warn' | 'error' | 'fatal';
  message: string;
  messageHash?: string;
  timestamp: string;
  receivedAt?: string;
  module: string;
  file?: string;
  line?: number;
  function?: string;
  threadId?: string;
  correlationId?: string;
  context: Record<string, unknown>;
  redaction?: {
    fieldsRedacted: string[];
    patternsMatched: string[];
  };
}

export interface QueryTracesOptions {
  sessionId: string;
  productId: string;
  startTime?: string;
  endTime?: string;
  name?: string;
  status?: string;
  limit?: number;
  offset?: number;
}

export interface QueryLogsOptions {
  sessionId: string;
  productId: string;
  levels?: ('debug' | 'info' | 'warn' | 'error' | 'fatal')[];
  module?: string;
  search?: string;
  startTime?: string;
  endTime?: string;
  limit?: number;
  offset?: number;
}

// =============================================================================
// Client Factory
// =============================================================================

export interface DiagnosticsClientConfig {
  baseUrl: string;
  productId: string;
  getAuthToken: () => string | null;
}

export function createDiagnosticsClient(config: DiagnosticsClientConfig) {
  const client = createApiClient({
    baseUrl: config.baseUrl,
    getToken: config.getAuthToken,
  }) as ApiClient;

  return {
    // -------------------------------------------------------------------------
    // Sessions
    // -------------------------------------------------------------------------

    async querySessions(options: QuerySessionsOptions): Promise<QuerySessionsResult> {
      const params = new URLSearchParams();
      params.set('productId', options.productId);
      if (options.status) params.set('status', options.status);
      if (options.targetUserId) params.set('targetUserId', options.targetUserId);
      if (options.targetDeviceId) params.set('targetDeviceId', options.targetDeviceId);
      if (options.startDate) params.set('startDate', options.startDate);
      if (options.endDate) params.set('endDate', options.endDate);
      if (options.limit) params.set('limit', options.limit.toString());
      if (options.offset) params.set('offset', options.offset.toString());

      const result = await client.safeFetch<QuerySessionsResult>(
        `/api/diagnostics/sessions?${params.toString()}`
      );
      if (result.error) throw new Error(result.error);
      return result.data!;
    },

    async createSession(request: CreateSessionRequest): Promise<DebugSession> {
      const result = await client.safeFetch<DebugSession>('/api/diagnostics/sessions', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(request),
      });
      if (result.error) throw new Error(result.error);
      return result.data!;
    },

    async getSession(sessionId: string): Promise<DebugSession> {
      const result = await client.safeFetch<DebugSession>(`/api/diagnostics/sessions/${sessionId}`);
      if (result.error) throw new Error(result.error);
      return result.data!;
    },

    async updateSession(sessionId: string, request: UpdateSessionRequest): Promise<DebugSession> {
      const result = await client.safeFetch<DebugSession>(
        `/api/diagnostics/sessions/${sessionId}`,
        {
          method: 'PATCH',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(request),
        }
      );
      if (result.error) throw new Error(result.error);
      return result.data!;
    },

    async cancelSession(sessionId: string, reason?: string): Promise<void> {
      const result = await client.safeFetch<void>(`/api/diagnostics/sessions/${sessionId}`, {
        method: 'DELETE',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ reason }),
      });
      if (result.error) throw new Error(result.error);
    },

    // -------------------------------------------------------------------------
    // Traces
    // -------------------------------------------------------------------------

    async getTraces(options: QueryTracesOptions): Promise<{ traces: TraceSpan[]; total: number }> {
      const params = new URLSearchParams();
      params.set('productId', options.productId);
      if (options.startTime) params.set('startTime', options.startTime);
      if (options.endTime) params.set('endTime', options.endTime);
      if (options.name) params.set('name', options.name);
      if (options.status) params.set('status', options.status);
      if (options.limit) params.set('limit', options.limit.toString());
      if (options.offset) params.set('offset', options.offset.toString());

      const result = await client.safeFetch<{ traces: TraceSpan[]; total: number }>(
        `/api/diagnostics/sessions/${options.sessionId}/traces?${params.toString()}`
      );
      if (result.error) throw new Error(result.error);
      return result.data!;
    },

    // -------------------------------------------------------------------------
    // Logs
    // -------------------------------------------------------------------------

    async getLogs(options: QueryLogsOptions): Promise<{ logs: LogEntry[]; total: number }> {
      const params = new URLSearchParams();
      params.set('productId', options.productId);
      if (options.levels) params.set('levels', options.levels.join(','));
      if (options.module) params.set('module', options.module);
      if (options.search) params.set('search', options.search);
      if (options.startTime) params.set('startTime', options.startTime);
      if (options.endTime) params.set('endTime', options.endTime);
      if (options.limit) params.set('limit', options.limit.toString());
      if (options.offset) params.set('offset', options.offset.toString());

      const result = await client.safeFetch<{ logs: LogEntry[]; total: number }>(
        `/api/diagnostics/sessions/${options.sessionId}/logs?${params.toString()}`
      );
      if (result.error) throw new Error(result.error);
      return result.data!;
    },

    // -------------------------------------------------------------------------
    // Screenshots
    // -------------------------------------------------------------------------

    async getScreenshots(
      sessionId: string,
      productId: string
    ): Promise<
      Array<{
        id: string;
        blobUrl: string;
        capturedAt: string;
        trigger: string;
        width: number;
        height: number;
      }>
    > {
      const params = new URLSearchParams();
      params.set('productId', productId);

      const result = await client.safeFetch<
        Array<{
          id: string;
          blobUrl: string;
          capturedAt: string;
          trigger: string;
          width: number;
          height: number;
        }>
      >(`/api/diagnostics/sessions/${sessionId}/screenshots?${params.toString()}`);
      if (result.error) throw new Error(result.error);
      return result.data!;
    },
  };
}

export type DiagnosticsClient = ReturnType<typeof createDiagnosticsClient>;
