import {
  AuditLogEntry,
  AuditSearchFilters,
  AuditExportRequest,
  SavedSearch,
  ComplianceReport,
  RemediationTask,
  Attestation,
  AuditDashboardStats,
  AuditVisualizationData
} from '@/types/audit';

const API_BASE_URL = process.env.NODE_ENV === 'production' ? '/api' : 'http://localhost:8080';

class ApiError extends Error {
  constructor(
    message: string,
    public status: number,
    public statusText: string,
    public response?: any
  ) {
    super(message);
    this.name = 'ApiError';
  }
}

async function apiRequest<T>(
  endpoint: string,
  options: RequestInit = {}
): Promise<T> {
  const url = `${API_BASE_URL}${endpoint}`;

  const response = await fetch(url, {
    headers: {
      'Content-Type': 'application/json',
      ...options.headers,
    },
    credentials: 'include',
    ...options,
  });

  if (!response.ok) {
    const errorData = await response.json().catch(() => ({}));
    throw new ApiError(
      errorData.message || `HTTP ${response.status}: ${response.statusText}`,
      response.status,
      response.statusText,
      errorData
    );
  }

  return response.json();
}

export const auditApi = {
  // Audit Log Operations
  async getLogs(filters: Partial<AuditSearchFilters>, page = 0, limit = 50): Promise<{
    logs: AuditLogEntry[];
    total: number;
    page: number;
    limit: number;
    hasMore: boolean;
  }> {
    const params = new URLSearchParams({
      page: page.toString(),
      limit: limit.toString(),
      ...Object.entries(filters).reduce((acc, [key, value]) => {
        if (value !== undefined && value !== null) {
          if (Array.isArray(value)) {
            acc[key] = value.join(',');
          } else if (value instanceof Date) {
            acc[key] = value.toISOString();
          } else {
            acc[key] = value.toString();
          }
        }
        return acc;
      }, {} as Record<string, string>)
    });

    return apiRequest(`/audit/logs?${params.toString()}`);
  },

  async getLog(id: string): Promise<AuditLogEntry> {
    return apiRequest(`/audit/logs/${id}`);
  },

  async searchLogs(query: string, filters: Partial<AuditSearchFilters>): Promise<{
    logs: AuditLogEntry[];
    total: number;
    suggestions: string[];
  }> {
    return apiRequest('/audit/search', {
      method: 'POST',
      body: JSON.stringify({ query, filters }),
    });
  },

  // Real-time streaming
  createWebSocket(onMessage: (message: any) => void): WebSocket {
    const wsUrl = API_BASE_URL.replace('http', 'ws') + '/audit/stream';
    const ws = new WebSocket(wsUrl);

    ws.onmessage = (event) => {
      try {
        const message = JSON.parse(event.data);
        onMessage(message);
      } catch (error) {
        console.error('Failed to parse WebSocket message:', error);
      }
    };

    return ws;
  },

  // Export Operations
  async exportLogs(request: AuditExportRequest): Promise<Blob> {
    const response = await fetch(`${API_BASE_URL}/audit/export`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      credentials: 'include',
      body: JSON.stringify(request),
    });

    if (!response.ok) {
      throw new ApiError(
        'Export failed',
        response.status,
        response.statusText
      );
    }

    return response.blob();
  },

  // Saved Searches
  async getSavedSearches(): Promise<SavedSearch[]> {
    return apiRequest('/audit/saved-searches');
  },

  async createSavedSearch(search: Omit<SavedSearch, 'id' | 'createdAt' | 'lastUsed' | 'useCount'>): Promise<SavedSearch> {
    return apiRequest('/audit/saved-searches', {
      method: 'POST',
      body: JSON.stringify(search),
    });
  },

  async updateSavedSearch(id: string, search: Partial<SavedSearch>): Promise<SavedSearch> {
    return apiRequest(`/audit/saved-searches/${id}`, {
      method: 'PUT',
      body: JSON.stringify(search),
    });
  },

  async deleteSavedSearch(id: string): Promise<void> {
    return apiRequest(`/audit/saved-searches/${id}`, {
      method: 'DELETE',
    });
  },

  // Dashboard and Statistics
  async getDashboardStats(period?: 'hour' | 'day' | 'week' | 'month'): Promise<AuditDashboardStats> {
    const params = period ? `?period=${period}` : '';
    return apiRequest(`/audit/dashboard/stats${params}`);
  },

  async getVisualizationData(filters: Partial<AuditSearchFilters>): Promise<AuditVisualizationData> {
    return apiRequest('/audit/dashboard/visualization', {
      method: 'POST',
      body: JSON.stringify(filters),
    });
  },

  // Compliance Operations
  async getComplianceReports(): Promise<ComplianceReport[]> {
    return apiRequest('/compliance/reports');
  },

  async getComplianceReport(id: string): Promise<ComplianceReport> {
    return apiRequest(`/compliance/reports/${id}`);
  },

  async generateComplianceReport(
    type: 'soc2' | 'hipaa' | 'pci' | 'gdpr' | 'custom',
    period: { start: Date; end: Date },
    template?: string
  ): Promise<{ reportId: string; status: 'generating' | 'completed' | 'failed' }> {
    return apiRequest('/compliance/reports/generate', {
      method: 'POST',
      body: JSON.stringify({
        type,
        period: {
          start: period.start.toISOString(),
          end: period.end.toISOString(),
        },
        template,
      }),
    });
  },

  async getComplianceTemplates(): Promise<Array<{ id: string; name: string; type: string; description: string }>> {
    return apiRequest('/compliance/templates');
  },

  // Remediation Operations
  async getRemediationTasks(filters?: {
    status?: string;
    priority?: string;
    assignee?: string;
  }): Promise<RemediationTask[]> {
    const params = filters ? '?' + new URLSearchParams(filters).toString() : '';
    return apiRequest(`/remediation/tasks${params}`);
  },

  async getRemediationTask(id: string): Promise<RemediationTask> {
    return apiRequest(`/remediation/tasks/${id}`);
  },

  async createRemediationTask(task: Omit<RemediationTask, 'id' | 'createdAt'>): Promise<RemediationTask> {
    return apiRequest('/remediation/tasks', {
      method: 'POST',
      body: JSON.stringify(task),
    });
  },

  async updateRemediationTask(id: string, updates: Partial<RemediationTask>): Promise<RemediationTask> {
    return apiRequest(`/remediation/tasks/${id}`, {
      method: 'PUT',
      body: JSON.stringify(updates),
    });
  },

  // Attestation Operations
  async getAttestations(): Promise<Attestation[]> {
    return apiRequest('/attestations');
  },

  async getAttestation(id: string): Promise<Attestation> {
    return apiRequest(`/attestations/${id}`);
  },

  async createAttestation(attestation: Omit<Attestation, 'id' | 'createdAt'>): Promise<Attestation> {
    return apiRequest('/attestations', {
      method: 'POST',
      body: JSON.stringify(attestation),
    });
  },

  async signAttestation(id: string, signature: string): Promise<Attestation> {
    return apiRequest(`/attestations/${id}/sign`, {
      method: 'POST',
      body: JSON.stringify({ signature }),
    });
  },

  // Log Correlation
  async getCorrelatedLogs(requestId: string): Promise<AuditLogEntry[]> {
    return apiRequest(`/audit/correlation/request/${requestId}`);
  },

  async getLogsBySession(sessionId: string): Promise<AuditLogEntry[]> {
    return apiRequest(`/audit/correlation/session/${sessionId}`);
  },

  async getLogTrail(logId: string, depth = 5): Promise<{
    upstream: AuditLogEntry[];
    downstream: AuditLogEntry[];
  }> {
    return apiRequest(`/audit/correlation/trail/${logId}?depth=${depth}`);
  },

  // Log Retention and Archival
  async getRetentionPolicies(): Promise<Array<{
    id: string;
    name: string;
    description: string;
    retentionDays: number;
    archiveDays: number;
    filters: AuditSearchFilters;
    enabled: boolean;
  }>> {
    return apiRequest('/audit/retention/policies');
  },

  async updateRetentionPolicy(id: string, policy: any): Promise<void> {
    return apiRequest(`/audit/retention/policies/${id}`, {
      method: 'PUT',
      body: JSON.stringify(policy),
    });
  },

  async getArchivedLogs(filters: Partial<AuditSearchFilters>): Promise<{
    logs: AuditLogEntry[];
    total: number;
  }> {
    const params = new URLSearchParams(
      Object.entries(filters).reduce((acc, [key, value]) => {
        if (value !== undefined && value !== null) {
          acc[key] = Array.isArray(value) ? value.join(',') : value.toString();
        }
        return acc;
      }, {} as Record<string, string>)
    );

    return apiRequest(`/audit/archived?${params.toString()}`);
  },

  // Health and Status
  async getHealthStatus(): Promise<{
    status: 'healthy' | 'unhealthy' | 'degraded';
    version: string;
    uptime: number;
    database: { connected: boolean; latency: number };
    websocket: { connected: boolean; clients: number };
    storage: { available: number; used: number };
  }> {
    return apiRequest('/health');
  },
};

export default auditApi;
export { ApiError };
