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

const crossplaneAPI = process.env.NEXT_PUBLIC_CROSSPLANE_API || 'http://localhost:8080';

// Error types
export class CrossplaneError extends Error {
  constructor(
    message: string,
    public statusCode?: number,
    public code?: string
  ) {
    super(message);
    this.name = 'CrossplaneError';
    Object.setPrototypeOf(this, CrossplaneError.prototype);
  }
}

function handleAxiosError(error: unknown): never {
  if (axios.isAxiosError(error)) {
    const axiosError = error as AxiosError<{ message?: string }>;
    const statusCode = axiosError.response?.status;
    const message = (axiosError.response?.data as { message?: string })?.message || axiosError.message || 'An error occurred';
    
    throw new CrossplaneError(message, statusCode, axiosError.code);
  }
  
  if (error instanceof Error) {
    throw new CrossplaneError(error.message);
  }
  
  throw new CrossplaneError('An unknown error occurred');
}

export interface CrossplaneClient {
  getVMs(): Promise<VM[]>;
  getVM(name: string): Promise<VM>;
  createVM(spec: VMSpec): Promise<VM>;
  updateVM(name: string, spec: Partial<VMSpec>): Promise<VM>;
  deleteVM(name: string): Promise<void>;
}

export interface VM {
  metadata: {
    name: string;
    namespace: string;
    creationTimestamp: string;
  };
  spec: VMSpec;
  status: {
    vmId?: number;
    state?: string;
    ipAddress?: string;
    conditions?: Array<{
      type: string;
      status: string;
      reason?: string;
      message?: string;
    }>;
  };
}

export interface VMSpec {
  forProvider: {
    node: string;
    name: string;
    cpu: number;
    memory: string;
    disk: string;
    storage: string;
    network: string;
    image: string;
    site: string;
    userData?: string;
    sshKeys?: string[];
  };
  providerConfigRef: {
    name: string;
  };
}

class CrossplaneClientImpl implements CrossplaneClient {
  private client: AxiosInstance;

  constructor(accessToken?: string) {
    this.client = axios.create({
      baseURL: crossplaneAPI,
      headers: accessToken
        ? {
            Authorization: `Bearer ${accessToken}`,
          }
        : {},
    });
  }

  async getVMs(): Promise<VM[]> {
    try {
      const apiGroup = process.env.NEXT_PUBLIC_CROSSPLANE_API_GROUP || 'proxmox.sankofa.nexus'
      const response = await this.client.get(`/apis/${apiGroup}/v1alpha1/proxmoxvms`);
      return response.data.items || [];
    } catch (error) {
      handleAxiosError(error);
    }
  }

  async getVM(name: string): Promise<VM> {
    try {
      const apiGroup = process.env.NEXT_PUBLIC_CROSSPLANE_API_GROUP || 'proxmox.sankofa.nexus'
      const response = await this.client.get(
        `/apis/${apiGroup}/v1alpha1/proxmoxvms/${name}`
      );
      return response.data;
    } catch (error) {
      handleAxiosError(error);
    }
  }

  async createVM(spec: VMSpec): Promise<VM> {
    try {
      const apiGroup = process.env.NEXT_PUBLIC_CROSSPLANE_API_GROUP || 'proxmox.sankofa.nexus'
      const response = await this.client.post(`/apis/${apiGroup}/v1alpha1/proxmoxvms`, {
        apiVersion: `${apiGroup}/v1alpha1`,
        kind: 'ProxmoxVM',
        metadata: {
          name: spec.forProvider.name,
          namespace: 'default',
        },
        spec,
      });
      return response.data;
    } catch (error) {
      handleAxiosError(error);
    }
  }

  async updateVM(name: string, spec: Partial<VMSpec>): Promise<VM> {
    try {
      const apiGroup = process.env.NEXT_PUBLIC_CROSSPLANE_API_GROUP || 'proxmox.sankofa.nexus'
      const response = await this.client.patch(
        `/apis/${apiGroup}/v1alpha1/proxmoxvms/${name}`,
        {
          spec,
        },
        {
          headers: {
            'Content-Type': 'application/merge-patch+json',
          },
        }
      );
      return response.data;
    } catch (error) {
      handleAxiosError(error);
    }
  }

  async deleteVM(name: string): Promise<void> {
    try {
      const apiGroup = process.env.NEXT_PUBLIC_CROSSPLANE_API_GROUP || 'proxmox.sankofa.nexus'
      await this.client.delete(`/apis/${apiGroup}/v1alpha1/proxmoxvms/${name}`);
    } catch (error) {
      handleAxiosError(error);
    }
  }
}

export function createCrossplaneClient(accessToken?: string): CrossplaneClient {
  return new CrossplaneClientImpl(accessToken);
}

