/**
 * API Service for working with saved machines
 */

import { ApiClient } from '../utils/apiClient';
import { authService } from './auth-service';
import { log } from '../utils/logger';
import { API_CONFIG } from '../config/api';

export type Protocol = 'rdp' | 'ssh' | 'vnc' | 'telnet';

export interface ConnectionStats {
  total_connections: number;
  last_connection?: string;
  successful_connections: number;
  failed_connections: number;
}

export interface ConnectionRecordResponse {
  success: boolean;
  message: string;
  history_id: string;
}

export interface SavedMachineCreate {
  name: string;
  hostname: string;
  port: number;
  protocol: Protocol;
  os?: string;
  description?: string;
  tags?: string[];
  is_favorite?: boolean;
}

export interface SavedMachineUpdate {
  name?: string;
  hostname?: string;
  port?: number;
  protocol?: Protocol;
  os?: string;
  description?: string;
  tags?: string[];
  is_favorite?: boolean;
}

export interface SavedMachine {
  id: string;
  user_id: string;
  name: string;
  hostname: string;
  port: number;
  protocol: Protocol;
  os?: string;
  description?: string;
  tags: string[];
  is_favorite: boolean;
  created_at: string;
  updated_at: string;
  last_connected_at?: string;
  connection_stats?: ConnectionStats;
}

export interface SavedMachineList {
  total: number;
  machines: SavedMachine[];
}

/**
 * Service for working with saved machines
 */
export class SavedMachinesApiService {
  private static baseUrl = `${API_CONFIG.BASE_URL}/api/machines/saved`;

  /**
   * Get list of all user's saved machines
   */
  static async getSavedMachines(includeStats: boolean = false): Promise<SavedMachineList> {
    try {
      const headers = await authService.getAuthHeaders();
      
      log.info('saved-machines-api', 'Fetching saved machines', { includeStats });
      
      const response = await ApiClient.get<SavedMachineList>(
        `${this.baseUrl}?include_stats=${includeStats}`,
        { headers }
      );
      
      log.info('saved-machines-api', 'Saved machines fetched successfully', {
        total: response.total
      });
      
      return response;
    } catch (error) {
      log.error('saved-machines-api', 'Failed to fetch saved machines', { error });
      throw error;
    }
  }

  /**
   * Get specific machine by ID
   */
  static async getSavedMachine(machineId: string): Promise<SavedMachine> {
    try {
      const headers = await authService.getAuthHeaders();
      
      log.info('saved-machines-api', 'Fetching saved machine', { machineId });
      
      const response = await ApiClient.get<SavedMachine>(
        `${this.baseUrl}/${machineId}`,
        { headers }
      );
      
      log.info('saved-machines-api', 'Saved machine fetched successfully', {
        machineId,
        name: response.name
      });
      
      return response;
    } catch (error) {
      log.error('saved-machines-api', 'Failed to fetch saved machine', {
        machineId,
        error
      });
      throw error;
    }
  }

  /**
   * Create new saved machine
   */
  static async createSavedMachine(machine: SavedMachineCreate): Promise<SavedMachine> {
    try {
      const headers = await authService.getAuthHeaders();
      
      log.info('saved-machines-api', 'Creating saved machine', {
        name: machine.name,
        hostname: machine.hostname,
        protocol: machine.protocol
      });
      
      const response = await ApiClient.post<SavedMachine>(
        this.baseUrl,
        machine,
        { headers }
      );
      
      log.info('saved-machines-api', 'Saved machine created successfully', {
        machineId: response.id,
        name: response.name
      });
      
      return response;
    } catch (error) {
      log.error('saved-machines-api', 'Failed to create saved machine', {
        name: machine.name,
        error
      });
      throw error;
    }
  }

  /**
   * Update saved machine
   */
  static async updateSavedMachine(
    machineId: string,
    updates: SavedMachineUpdate
  ): Promise<SavedMachine> {
    try {
      const headers = await authService.getAuthHeaders();
      
      log.info('saved-machines-api', 'Updating saved machine', {
        machineId,
        updates: Object.keys(updates)
      });
      
      const response = await ApiClient.put<SavedMachine>(
        `${this.baseUrl}/${machineId}`,
        updates,
        { headers }
      );
      
      log.info('saved-machines-api', 'Saved machine updated successfully', {
        machineId,
        name: response.name
      });
      
      return response;
    } catch (error) {
      log.error('saved-machines-api', 'Failed to update saved machine', {
        machineId,
        error
      });
      throw error;
    }
  }

  /**
   * Delete saved machine
   */
  static async deleteSavedMachine(machineId: string): Promise<void> {
    try {
      const headers = await authService.getAuthHeaders();
      
      log.info('saved-machines-api', 'Deleting saved machine', { machineId });
      
      await ApiClient.delete(
        `${this.baseUrl}/${machineId}`,
        { headers }
      );
      
      log.info('saved-machines-api', 'Saved machine deleted successfully', {
        machineId
      });
    } catch (error) {
      log.error('saved-machines-api', 'Failed to delete saved machine', {
        machineId,
        error
      });
      throw error;
    }
  }

  /**
   * Record connection to machine
   */
  static async connectToSavedMachine(
    machineId: string
  ): Promise<ConnectionRecordResponse> {
    try {
      const headers = await authService.getAuthHeaders();
      
      log.info('saved-machines-api', 'Recording connection to saved machine', {
        machineId
      });
      
      const response = await ApiClient.post<ConnectionRecordResponse>(
        `${this.baseUrl}/${machineId}/connect`,
        {},
        { headers }
      );
      
      log.info('saved-machines-api', 'Connection recorded successfully', {
        machineId,
        historyId: response.history_id
      });
      
      return response;
    } catch (error) {
      log.error('saved-machines-api', 'Failed to record connection', {
        machineId,
        error
      });
      throw error;
    }
  }

  /**
   * Toggle favorite status
   */
  static async toggleFavorite(
    machineId: string,
    isFavorite: boolean
  ): Promise<SavedMachine> {
    return this.updateSavedMachine(machineId, { is_favorite: isFavorite });
  }

  /**
   * Update machine tags
   */
  static async updateTags(machineId: string, tags: string[]): Promise<SavedMachine> {
    return this.updateSavedMachine(machineId, { tags });
  }

  /**
   * Filter machines by tags
   */
  static filterByTags(machines: SavedMachine[], tags: string[]): SavedMachine[] {
    if (!tags || tags.length === 0) {
      return machines;
    }
    
    return machines.filter((machine) => tags.some((tag) => machine.tags.includes(tag)));
  }

  /**
   * Filter machines by protocol
   */
  static filterByProtocol(machines: SavedMachine[], protocol: string): SavedMachine[] {
    return machines.filter((machine) => machine.protocol === protocol);
  }

  /**
   * Filter only favorites
   */
  static filterFavorites(machines: SavedMachine[]): SavedMachine[] {
    return machines.filter((machine) => machine.is_favorite);
  }

  /**
   * Search by name or hostname
   */
  static search(machines: SavedMachine[], query: string): SavedMachine[] {
    if (!query) {
      return machines;
    }
    
    const lowerQuery = query.toLowerCase();
    return machines.filter(
      (machine) =>
        machine.name.toLowerCase().includes(lowerQuery) ||
        machine.hostname.toLowerCase().includes(lowerQuery) ||
        machine.description?.toLowerCase().includes(lowerQuery)
    );
  }
}

export const savedMachinesApi = SavedMachinesApiService;

