import type { SourceAuth, ProjectSource } from "../types";

export interface CredentialProvider {
  /**
   * Get credentials for a specific project
   */
  getCredentials(projectId: string, source: ProjectSource): Promise<any>;
  
  /**
   * Store credentials securely
   */
  storeCredentials(projectId: string, credentials: any): Promise<void>;
  
  /**
   * Remove stored credentials
   */
  removeCredentials(projectId: string): Promise<void>;
}

/**
 * Manages credentials for different project sources
 */
export class CredentialManager {
  private providers = new Map<string, CredentialProvider>();
  private memoryCache = new Map<string, any>();

  /**
   * Register a credential provider
   */
  registerProvider(name: string, provider: CredentialProvider): void {
    this.providers.set(name, provider);
  }

  /**
   * Get credentials for a project source
   */
  async getCredentials(projectId: string, source: ProjectSource): Promise<any> {
    // Check memory cache first
    const cacheKey = `${projectId}:${source.type}`;
    if (this.memoryCache.has(cacheKey)) {
      return this.memoryCache.get(cacheKey);
    }

    // Use provider if available
    const provider = this.providers.get(source.type);
    if (provider) {
      const credentials = await provider.getCredentials(projectId, source);
      this.memoryCache.set(cacheKey, credentials);
      return credentials;
    }

    // Fallback to source auth if provided
    if (source.auth) {
      return this.extractCredentials(source.auth);
    }

    // Return empty object if no credentials needed
    return {};
  }

  /**
   * Extract credentials from auth config
   */
  private extractCredentials(auth: SourceAuth): any {
    switch (auth.type) {
      case "bearer":
        return { token: auth.credentials.token };
      case "basic":
        return {
          username: auth.credentials.username,
          password: auth.credentials.password
        };
      case "token":
        return { apiKey: auth.credentials.apiKey };
      case "oauth2":
        return {
          accessToken: auth.credentials.accessToken,
          refreshToken: auth.credentials.refreshToken
        };
      default:
        return auth.credentials;
    }
  }

  /**
   * Clear cached credentials
   */
  clearCache(projectId?: string): void {
    if (projectId) {
      // Clear specific project
      for (const [key] of this.memoryCache) {
        if (key.startsWith(`${projectId}:`)) {
          this.memoryCache.delete(key);
        }
      }
    } else {
      // Clear all
      this.memoryCache.clear();
    }
  }
}

/**
 * Browser-based credential provider using Web Crypto API
 */
export class BrowserCredentialProvider implements CredentialProvider {
  private dbName = "@firesystem/credentials";
  private storeName = "credentials";

  async getCredentials(projectId: string, source: ProjectSource): Promise<any> {
    // For demo purposes, return config as-is
    // In production, this would decrypt from secure storage
    return source.config;
  }

  async storeCredentials(projectId: string, credentials: any): Promise<void> {
    // In production, encrypt before storing
    console.warn("Storing credentials in browser - consider security implications");
  }

  async removeCredentials(projectId: string): Promise<void> {
    // Remove from secure storage
  }
}

/**
 * Environment variable credential provider (for Node.js)
 */
export class EnvCredentialProvider implements CredentialProvider {
  async getCredentials(projectId: string, source: ProjectSource): Promise<any> {
    const prefix = `FIRESYSTEM_${source.type.toUpperCase()}_`;
    
    switch (source.type) {
      case "s3":
        return {
          accessKeyId: process.env[`${prefix}ACCESS_KEY_ID`],
          secretAccessKey: process.env[`${prefix}SECRET_ACCESS_KEY`],
          region: process.env[`${prefix}REGION`] || "us-east-1",
          bucket: source.config.bucket // Bucket from config
        };
      
      case "github":
        return {
          token: process.env[`${prefix}TOKEN`] || process.env.GITHUB_TOKEN
        };
      
      case "api":
        return {
          apiKey: process.env[`${prefix}API_KEY`],
          baseUrl: source.config.baseUrl
        };
      
      default:
        return source.config;
    }
  }

  async storeCredentials(): Promise<void> {
    throw new Error("Cannot store credentials in environment variables");
  }

  async removeCredentials(): Promise<void> {
    throw new Error("Cannot remove credentials from environment variables");
  }
}

/**
 * Interactive credential provider that prompts user
 */
export class InteractiveCredentialProvider implements CredentialProvider {
  constructor(
    private prompter: (message: string, secure?: boolean) => Promise<string>
  ) {}

  async getCredentials(projectId: string, source: ProjectSource): Promise<any> {
    console.log(`Credentials needed for ${source.type} project: ${projectId}`);
    
    switch (source.type) {
      case "s3":
        return {
          accessKeyId: await this.prompter("AWS Access Key ID:"),
          secretAccessKey: await this.prompter("AWS Secret Access Key:", true),
          region: await this.prompter("AWS Region (default: us-east-1):") || "us-east-1",
          bucket: source.config.bucket
        };
      
      case "github":
        return {
          token: await this.prompter("GitHub Personal Access Token:", true)
        };
      
      case "api":
        return {
          apiKey: await this.prompter("API Key:", true),
          baseUrl: source.config.baseUrl
        };
      
      default:
        return source.config;
    }
  }

  async storeCredentials(): Promise<void> {
    // No storage in interactive mode
  }

  async removeCredentials(): Promise<void> {
    // No storage in interactive mode
  }
}