/**
 * Service Type Definitions
 * Provides full type safety for all injected services
 */

// Import actual service types from their packages
// These are type-only imports, so no runtime dependencies

// Logger types
export interface Logger {
  info(message: string, meta?: Record<string, unknown>): void;
  error(message: string, meta?: Record<string, unknown>): void;
  warn(message: string, meta?: Record<string, unknown>): void;
  debug(message: string, meta?: Record<string, unknown>): void;
  trace(message: string, meta?: Record<string, unknown>): void;
  fatal(message: string, meta?: Record<string, unknown>): void;
  child?(name: string, context?: Record<string, unknown>): Logger;
}

// Cache types - matches the actual CacheProvider interface from @stock-bot/cache
export interface CacheProvider {
  get<T>(key: string): Promise<T | null>;
  set<T>(
    key: string,
    value: T,
    options?:
      | number
      | {
          ttl?: number;
          preserveTTL?: boolean;
          onlyIfExists?: boolean;
          onlyIfNotExists?: boolean;
          getOldValue?: boolean;
        }
  ): Promise<T | null>;
  del(key: string): Promise<void>;
  exists(key: string): Promise<boolean>;
  clear(): Promise<void>;
  keys(pattern: string): Promise<string[]>;
  getStats(): CacheStats;
  health(): Promise<boolean>;
  waitForReady(timeout?: number): Promise<void>;
  isReady(): boolean;
}

export interface CacheStats {
  hits: number;
  misses: number;
  errors: number;
  hitRate: number;
  total: number;
  uptime: number;
}

// Queue Manager types
export interface QueueManager {
  getQueue(queueName: string, options?: any): Queue;
  createQueue(queueName: string, options?: any): Queue;
  getOrCreateQueue(queueName: string, options?: any): Queue;
  queueExists(queueName: string): boolean;
  deleteQueue(queueName: string): Promise<void>;
  getQueueStats(queueName?: string): Promise<any>;
  getBatchCache(queueName: string): CacheProvider | null;
  getRateLimiter(): any;
  checkRateLimit(key: string, rule?: string): Promise<{ allowed: boolean; retryAfter?: number }>;
  shutdown(): Promise<void>;
}

export interface Queue {
  add(name: string, data: any, opts?: any): Promise<any>;
  addBulk(jobs: Array<{ name: string; data: any; opts?: any }>): Promise<any[]>;
  process(concurrency: number, processor: any): Promise<void>;
  process(name: string, concurrency: number, processor: any): Promise<void>;
  process(processor: any): Promise<void>;
  on(event: string, listener: (...args: any[]) => void): void;
  pause(): Promise<void>;
  resume(): Promise<void>;
  close(): Promise<void>;
  clean(grace: number, limit?: number, type?: string): Promise<string[]>;
  getJobs(types: string[], start?: number, end?: number, asc?: boolean): Promise<any[]>;
  getJobCounts(...types: string[]): Promise<Record<string, number>>;
  name: string;
}

// MongoDB types
export interface MongoDBClient {
  connect(): Promise<void>;
  disconnect(): Promise<void>;
  isConnected(): boolean;
  getDb(dbName?: string): any; // MongoDB Db type
  collection(name: string, dbName?: string): any; // MongoDB Collection
  createCollection(name: string, options?: any, dbName?: string): Promise<void>;
  dropCollection(name: string, dbName?: string): Promise<boolean>;
  listCollections(dbName?: string): Promise<Array<{ name: string; type: string }>>;
  find<T = any>(collection: string, filter?: any, options?: any, dbName?: string): Promise<T[]>;
  findOne<T = any>(
    collection: string,
    filter: any,
    options?: any,
    dbName?: string
  ): Promise<T | null>;
  insertOne<T = any>(collection: string, document: T, options?: any, dbName?: string): Promise<any>;
  insertMany<T = any>(
    collection: string,
    documents: T[],
    options?: any,
    dbName?: string
  ): Promise<any>;
  updateOne(
    collection: string,
    filter: any,
    update: any,
    options?: any,
    dbName?: string
  ): Promise<any>;
  updateMany(
    collection: string,
    filter: any,
    update: any,
    options?: any,
    dbName?: string
  ): Promise<any>;
  deleteOne(collection: string, filter: any, options?: any, dbName?: string): Promise<any>;
  deleteMany(collection: string, filter: any, options?: any, dbName?: string): Promise<any>;
  countDocuments(collection: string, filter?: any, options?: any, dbName?: string): Promise<number>;
  aggregate<T = any>(
    collection: string,
    pipeline: any[],
    options?: any,
    dbName?: string
  ): Promise<T[]>;
  createIndex(collection: string, indexSpec: any, options?: any, dbName?: string): Promise<string>;
  dropIndex(collection: string, indexName: string, options?: any, dbName?: string): Promise<void>;
  listIndexes(collection: string, dbName?: string): Promise<any[]>;
  batchUpsert<T = any>(
    collection: string,
    documents: T[],
    uniqueKeys: string | string[],
    options?: any,
    dbName?: string
  ): Promise<any>;
  batchUpsertStock<T = any>(
    collection: string,
    documents: T[],
    uniqueKeys: string | string[],
    options?: any
  ): Promise<any>;
  batchUpsertTrading<T = any>(
    collection: string,
    documents: T[],
    uniqueKeys: string | string[],
    options?: any
  ): Promise<any>;
  batchUpsertAnalytics<T = any>(
    collection: string,
    documents: T[],
    uniqueKeys: string | string[],
    options?: any
  ): Promise<any>;
}

// PostgreSQL types
export interface PostgresClient {
  query<T = any>(text: string, params?: any[]): Promise<{ rows: T[]; rowCount: number }>;
  queryOne<T = any>(text: string, params?: any[]): Promise<T | null>;
  execute(text: string, params?: any[]): Promise<{ rowCount: number }>;
  transaction<T>(callback: (client: any) => Promise<T>): Promise<T>;
  insert(table: string, data: Record<string, any>, returning?: string | string[]): Promise<any>;
  update(
    table: string,
    data: Record<string, any>,
    where: Record<string, any>,
    returning?: string | string[]
  ): Promise<any>;
  delete(table: string, where: Record<string, any>, returning?: string | string[]): Promise<any>;
  upsert(
    table: string,
    data: Record<string, any>,
    conflictColumns: string | string[],
    returning?: string | string[]
  ): Promise<any>;
  batchInsert(
    table: string,
    data: Record<string, any>[],
    returning?: string | string[]
  ): Promise<any[]>;
  batchUpsert(
    table: string,
    data: Record<string, any>[],
    conflictColumns: string | string[],
    returning?: string | string[]
  ): Promise<any[]>;
  exists(table: string, where: Record<string, any>): Promise<boolean>;
  count(table: string, where?: Record<string, any>): Promise<number>;
  getClient(): Promise<any>;
  releaseClient(client: any): void;
  end(): Promise<void>;
  isConnected(): boolean;
}

// QuestDB types
export interface QuestDBClient {
  connect(): Promise<void>;
  disconnect(): Promise<void>;
  isConnected(): boolean;
  query<T = any>(sql: string): Promise<T[]>;
  insert(table: string, data: Record<string, any> | Record<string, any>[]): Promise<void>;
  insertBatch(table: string, data: Record<string, any>[]): Promise<void>;
  createTable(tableDef: any): Promise<void>;
  dropTable(tableName: string): Promise<void>;
  tableExists(tableName: string): Promise<boolean>;
  getTableSchema(tableName: string): Promise<any>;
  flush(): Promise<void>;
  insertWithTimestamp(
    table: string,
    data: Record<string, any>,
    timestamp?: Date | number
  ): Promise<void>;
  batchInsertWithTimestamp(
    table: string,
    data: Array<Record<string, any> & { timestamp?: Date | number }>
  ): Promise<void>;
}

// Browser types (Playwright)
export interface Browser {
  newPage(): Promise<Page>;
  newContext(options?: any): Promise<BrowserContext>;
  close(): Promise<void>;
  isConnected(): boolean;
  version(): string;
}

export interface BrowserContext {
  newPage(): Promise<Page>;
  close(): Promise<void>;
  pages(): Page[];
  setDefaultTimeout(timeout: number): void;
  setDefaultNavigationTimeout(timeout: number): void;
  addCookies(cookies: any[]): Promise<void>;
  clearCookies(): Promise<void>;
}

export interface Page {
  goto(url: string, options?: any): Promise<any>;
  waitForSelector(selector: string, options?: any): Promise<any>;
  click(selector: string, options?: any): Promise<void>;
  fill(selector: string, value: string, options?: any): Promise<void>;
  evaluate<T = any>(pageFunction: any, arg?: any): Promise<T>;
  evaluateHandle<T = any>(pageFunction: any, arg?: any): Promise<T>;
  screenshot(options?: any): Promise<Buffer>;
  pdf(options?: any): Promise<Buffer>;
  content(): Promise<string>;
  title(): Promise<string>;
  url(): string;
  close(): Promise<void>;
  waitForTimeout(timeout: number): Promise<void>;
  waitForLoadState(state?: string, options?: any): Promise<void>;
  locator(selector: string): any;
  $$(selector: string): Promise<any[]>;
  textContent(selector: string): Promise<string | null>;
}

// Proxy Manager types
export interface ProxyManager {
  getProxy(): string | null;
  getProxyInfo(): ProxyInfo | null;
  getProxies(count: number, key?: string): Promise<ProxyInfo[]>;
  releaseProxy(proxy: ProxyInfo | string): Promise<void>;
  markProxyFailed(proxy: ProxyInfo | string, reason?: string): Promise<void>;
  getStats(): ProxyStats;
  resetProxy(proxy: ProxyInfo | string): Promise<void>;
  blacklistProxy(proxy: ProxyInfo | string, duration?: number): Promise<void>;
  isBlacklisted(proxy: ProxyInfo | string): Promise<boolean>;
  refreshProxies(): Promise<void>;
}

// ProxyInfo should be imported from @stock-bot/proxy package
// to avoid duplication. Using minimal definition here for type compatibility
export interface ProxyInfo {
  host: string;
  port: number;
  protocol: 'http' | 'https';
  username?: string;
  password?: string;
  [key: string]: any; // Allow additional properties from proxy package
}

export interface ProxyStats {
  total: number;
  available: number;
  inUse: number;
  failed: number;
  blacklisted: number;
}

/**
 * Complete service types for dependency injection
 */
export interface ServiceTypes {
  logger: Logger;
  cache?: CacheProvider;
  globalCache?: CacheProvider;
  queueManager?: QueueManager;
  queue?: Queue; // Individual queue instance
  proxy?: ProxyManager;
  browser?: Browser;
  mongodb?: MongoDBClient;
  postgres?: PostgresClient;
  questdb?: QuestDBClient;
}
