import axios, { AxiosInstance, AxiosResponse } from 'axios';

// Types based on the KMS API
export interface Application {
  app_id: string;
  app_link: string;
  type: string[];
  callback_url: string;
  hmac_key: string;
  token_prefix?: string;
  token_renewal_duration: number;
  max_token_duration: number;
  owner: {
    type: string;
    name: string;
    owner: string;
  };
  created_at: string;
  updated_at: string;
}

export interface StaticToken {
  id: string;
  app_id: string;
  owner: {
    type: string;
    name: string;
    owner: string;
  };
  type: string;
  created_at: string;
  updated_at: string;
}

export interface CreateApplicationRequest {
  app_id: string;
  app_link: string;
  type: string[];
  callback_url: string;
  token_prefix?: string;
  token_renewal_duration: string;
  max_token_duration: string;
  owner: {
    type: string;
    name: string;
    owner: string;
  };
}

export interface CreateTokenRequest {
  owner: {
    type: string;
    name: string;
    owner: string;
  };
  permissions: string[];
}

export interface CreateTokenResponse {
  id: string;
  token: string;
  permissions: string[];
  created_at: string;
}

export interface PaginatedResponse<T> {
  data: T[];
  limit: number;
  offset: number;
  count: number;
}

export interface VerifyRequest {
  app_id: string;
  user_id?: string;
  token: string;
  permissions?: string[];
}

export interface VerifyResponse {
  valid: boolean;
  permitted: boolean;
  user_id?: string;
  permissions: string[];
  permission_results?: Record<string, boolean>;
  expires_at?: string;
  max_valid_at?: string;
  token_type: string;
  claims?: Record<string, string>;
  error?: string;
}

export interface AuditEvent {
  id: string;
  type: string;
  status: string;
  timestamp: string;
  actor_id?: string;
  actor_ip?: string;
  user_agent?: string;
  resource_id?: string;
  resource_type?: string;
  action: string;
  description: string;
  details?: Record<string, any>;
  request_id?: string;
  session_id?: string;
}

export interface AuditQueryParams {
  event_types?: string[];
  statuses?: string[];
  actor_id?: string;
  resource_id?: string;
  resource_type?: string;
  start_time?: string;
  end_time?: string;
  limit?: number;
  offset?: number;
  order_by?: string;
  order_desc?: boolean;
}

export interface AuditResponse {
  events: AuditEvent[];
  total: number;
  limit: number;
  offset: number;
}

export interface AuditStats {
  total_events: number;
  by_type: Record<string, number>;
  by_severity: Record<string, number>;
  by_status: Record<string, number>;
  by_time?: Record<string, number>;
}

export interface AuditStatsParams {
  event_types?: string[];
  start_time?: string;
  end_time?: string;
  group_by?: string;
}

class ApiService {
  private api: AxiosInstance;
  private baseURL: string;

  constructor() {
    this.baseURL = process.env.REACT_APP_API_URL || 'http://localhost:8080';
    
    this.api = axios.create({
      baseURL: this.baseURL,
      headers: {
        'Content-Type': 'application/json',
      },
    });

    // Add request interceptor to include user email header
    this.api.interceptors.request.use((config) => {
      // For demo purposes, we'll use a default user
      config.headers['X-User-Email'] = 'admin@example.com';
      return config;
    });

    // Add response interceptor for error handling
    this.api.interceptors.response.use(
      (response) => response,
      (error) => {
        console.error('API Error:', error);
        return Promise.reject(error);
      }
    );
  }

  // Applications
  async getApplications(limit: number = 50, offset: number = 0): Promise<PaginatedResponse<Application>> {
    const response = await this.api.get(`/api/applications?limit=${limit}&offset=${offset}`);
    return response.data;
  }

  async getApplication(appId: string): Promise<Application> {
    const response = await this.api.get(`/api/applications/${appId}`);
    return response.data;
  }

  async createApplication(data: CreateApplicationRequest): Promise<Application> {
    const response = await this.api.post('/api/applications', data);
    return response.data;
  }

  async updateApplication(appId: string, data: Partial<CreateApplicationRequest>): Promise<Application> {
    const response = await this.api.put(`/api/applications/${appId}`, data);
    return response.data;
  }

  async deleteApplication(appId: string): Promise<void> {
    await this.api.delete(`/api/applications/${appId}`);
  }

  // Tokens
  async getTokensForApplication(appId: string, limit: number = 50, offset: number = 0): Promise<PaginatedResponse<StaticToken>> {
    const response = await this.api.get(`/api/applications/${appId}/tokens?limit=${limit}&offset=${offset}`);
    return response.data;
  }

  async createToken(appId: string, data: CreateTokenRequest): Promise<CreateTokenResponse> {
    const response = await this.api.post(`/api/applications/${appId}/tokens`, data);
    return response.data;
  }

  async deleteToken(tokenId: string): Promise<void> {
    await this.api.delete(`/api/tokens/${tokenId}`);
  }

  // Token verification
  async verifyToken(data: VerifyRequest): Promise<VerifyResponse> {
    const response = await this.api.post('/api/verify', data);
    return response.data;
  }

  // Audit endpoints
  async getAuditEvents(params?: AuditQueryParams): Promise<AuditResponse> {
    const queryString = new URLSearchParams();
    
    if (params) {
      if (params.event_types?.length) {
        params.event_types.forEach(type => queryString.append('event_types', type));
      }
      if (params.statuses?.length) {
        params.statuses.forEach(status => queryString.append('statuses', status));
      }
      if (params.actor_id) queryString.set('actor_id', params.actor_id);
      if (params.resource_id) queryString.set('resource_id', params.resource_id);
      if (params.resource_type) queryString.set('resource_type', params.resource_type);
      if (params.start_time) queryString.set('start_time', params.start_time);
      if (params.end_time) queryString.set('end_time', params.end_time);
      if (params.limit) queryString.set('limit', params.limit.toString());
      if (params.offset) queryString.set('offset', params.offset.toString());
      if (params.order_by) queryString.set('order_by', params.order_by);
      if (params.order_desc !== undefined) queryString.set('order_desc', params.order_desc.toString());
    }

    const url = `/api/audit/events${queryString.toString() ? '?' + queryString.toString() : ''}`;
    const response = await this.api.get(url);
    return response.data;
  }

  async getAuditEvent(eventId: string): Promise<AuditEvent> {
    const response = await this.api.get(`/api/audit/events/${eventId}`);
    return response.data;
  }

  async getAuditStats(params?: AuditStatsParams): Promise<AuditStats> {
    const queryString = new URLSearchParams();
    
    if (params) {
      if (params.event_types?.length) {
        params.event_types.forEach(type => queryString.append('event_types', type));
      }
      if (params.start_time) queryString.set('start_time', params.start_time);
      if (params.end_time) queryString.set('end_time', params.end_time);
      if (params.group_by) queryString.set('group_by', params.group_by);
    }

    const url = `/api/audit/stats${queryString.toString() ? '?' + queryString.toString() : ''}`;
    const response = await this.api.get(url);
    return response.data;
  }
}

export const apiService = new ApiService();