/**
 * ArgoCD API Client
 * Handles communication with ArgoCD for GitOps status and management
 */

import axios, { AxiosInstance } from 'axios'

function errorMessage(error: unknown): string {
  if (error instanceof Error) return error.message
  return String(error)
}

export interface ArgoCDApplication {
  metadata: {
    name: string
    namespace: string
    uid: string
  }
  spec: {
    project: string
    source: {
      repoURL: string
      path?: string
      targetRevision?: string
    }
    destination: {
      server: string
      namespace: string
    }
    syncPolicy?: {
      automated?: {
        prune: boolean
        selfHeal: boolean
      }
      syncOptions?: string[]
    }
  }
  status: {
    health: {
      status: 'Healthy' | 'Degraded' | 'Progressing' | 'Suspended' | 'Missing' | 'Unknown'
      message?: string
    }
    sync: {
      status: 'Synced' | 'OutOfSync' | 'Unknown'
      revision?: string
    }
    conditions?: Array<{
      type: string
      message: string
      lastTransitionTime: string
    }>
  }
}

export interface ArgoCDSyncResult {
  resources: Array<{
    kind: string
    namespace: string
    name: string
    status: string
    message?: string
  }>
}

class ArgoCDClient {
  private client: AxiosInstance
  private baseURL: string

  constructor(accessToken?: string) {
    this.baseURL = process.env.NEXT_PUBLIC_ARGOCD_URL || 'http://localhost:8080'
    
    this.client = axios.create({
      baseURL: this.baseURL,
      headers: {
        'Content-Type': 'application/json',
        ...(accessToken && { Authorization: `Bearer ${accessToken}` }),
      },
    })
  }

  /**
   * Get all ArgoCD applications
   */
  async getApplications(): Promise<ArgoCDApplication[]> {
    try {
      const response = await this.client.get('/api/v1/applications')
      return response.data.items || []
    } catch (error: unknown) {
      throw new Error(`Failed to fetch applications: ${errorMessage(error)}`)
    }
  }

  /**
   * Get a specific ArgoCD application
   */
  async getApplication(name: string, namespace: string = 'argocd'): Promise<ArgoCDApplication> {
    try {
      const response = await this.client.get(`/api/v1/applications/${name}`, {
        params: { namespace },
      })
      return response.data
    } catch (error: unknown) {
      throw new Error(`Failed to fetch application: ${errorMessage(error)}`)
    }
  }

  /**
   * Sync an ArgoCD application
   */
  async syncApplication(
    name: string,
    namespace: string = 'argocd',
    prune: boolean = false,
    dryRun: boolean = false
  ): Promise<ArgoCDSyncResult> {
    try {
      const response = await this.client.post(
        `/api/v1/applications/${name}/sync`,
        {
          prune,
          dryRun,
        },
        {
          params: { namespace },
        }
      )
      return response.data
    } catch (error: unknown) {
      throw new Error(`Failed to sync application: ${errorMessage(error)}`)
    }
  }

  /**
   * Get application logs
   */
  async getApplicationLogs(
    name: string,
    namespace: string = 'argocd',
    tailLines: number = 100
  ): Promise<string[]> {
    try {
      const response = await this.client.get(`/api/v1/applications/${name}/logs`, {
        params: {
          namespace,
          tailLines,
        },
      })
      return response.data.logs || []
    } catch (error: unknown) {
      throw new Error(`Failed to fetch logs: ${errorMessage(error)}`)
    }
  }

  /**
   * Get application resource tree
   */
  async getApplicationResourceTree(
    name: string,
    namespace: string = 'argocd'
  ): Promise<unknown> {
    try {
      const response = await this.client.get(`/api/v1/applications/${name}/resource-tree`, {
        params: { namespace },
      })
      return response.data
    } catch (error: unknown) {
      throw new Error(`Failed to fetch resource tree: ${errorMessage(error)}`)
    }
  }
}

export function createArgoCDClient(accessToken?: string): ArgoCDClient {
  return new ArgoCDClient(accessToken)
}

