import axios from 'axios';
import type { AxiosInstance, AxiosResponse } from 'axios';

// Types for Frappe API responses
export interface FrappeResponse<T = any> {
  message: T;
  exc?: string;
  exc_type?: string;
}

export interface FrappeDocType {
  name: string;
  creation: string;
  modified: string;
  modified_by: string;
  owner: string;
  docstatus: number;
  idx: number;
  [key: string]: any;
}

export interface LoginCredentials {
  usr: string;
  pwd: string;
}

export interface UserDetails {
  full_name: string;
  email: string;
  user_image: string;
  roles: string[];
}

class FrappeAPIClient {
  private client: AxiosInstance;
  private baseURL: string;
  private siteName: string;

  constructor() {
    this.baseURL = import.meta.env.VITE_FRAPPE_BASE_URL || 'http://localhost:8000';
    this.siteName = import.meta.env.VITE_FRAPPE_SITE_NAME || 'seeraasm-med.seeraarabia.com';
    
    this.client = axios.create({
      baseURL: this.baseURL,
      timeout: parseInt(import.meta.env.VITE_API_TIMEOUT || '10000'),
      withCredentials: true, // Important for session cookies
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
      },
    });

    // Request interceptor to add site name to requests
    this.client.interceptors.request.use((config) => {
      if (config.url?.includes('/api/')) {
        config.url = `/${this.siteName}${config.url}`;
      }
      return config;
    });

    // Response interceptor for error handling
    this.client.interceptors.response.use(
      (response) => response,
      (error) => {
        if (error.response?.status === 401) {
          // Handle unauthorized - redirect to login
          window.location.href = '/login';
        }
        return Promise.reject(error);
      }
    );
  }

  // Authentication methods
  async login(credentials: LoginCredentials): Promise<FrappeResponse<UserDetails>> {
    const response: AxiosResponse<FrappeResponse<UserDetails>> = await this.client.post(
      '/api/method/login',
      credentials
    );
    return response.data;
  }

  async logout(): Promise<FrappeResponse> {
    const response: AxiosResponse<FrappeResponse> = await this.client.post(
      '/api/method/logout'
    );
    return response.data;
  }

  async getCurrentUser(): Promise<FrappeResponse<UserDetails>> {
    const response: AxiosResponse<FrappeResponse<UserDetails>> = await this.client.get(
      '/api/method/frappe.auth.get_logged_user'
    );
    return response.data;
  }

  // Generic API methods
  async callMethod(method: string, args: any = {}): Promise<FrappeResponse> {
    const response: AxiosResponse<FrappeResponse> = await this.client.post(
      `/api/method/${method}`,
      args
    );
    return response.data;
  }

  // Convenience method for GET requests
  async frappeGet(method: string, args: any = {}): Promise<FrappeResponse> {
    return this.callMethod(method, args);
  }

  // DocType operations
  async getDocTypeRecords(doctype: string, filters: any = {}, fields: string[] = []): Promise<FrappeResponse<FrappeDocType[]>> {
    const params = new URLSearchParams();
    
    if (Object.keys(filters).length > 0) {
      params.append('filters', JSON.stringify(filters));
    }
    
    if (fields.length > 0) {
      params.append('fields', JSON.stringify(fields));
    }

    const response: AxiosResponse<FrappeResponse<FrappeDocType[]>> = await this.client.get(
      `/api/resource/${doctype}?${params.toString()}`
    );
    return response.data;
  }

  async getDocTypeRecord(doctype: string, name: string): Promise<FrappeResponse<FrappeDocType>> {
    const response: AxiosResponse<FrappeResponse<FrappeDocType>> = await this.client.get(
      `/api/resource/${doctype}/${name}`
    );
    return response.data;
  }

  async createDocTypeRecord(doctype: string, data: any): Promise<FrappeResponse<FrappeDocType>> {
    const response: AxiosResponse<FrappeResponse<FrappeDocType>> = await this.client.post(
      `/api/resource/${doctype}`,
      data
    );
    return response.data;
  }

  async updateDocTypeRecord(doctype: string, name: string, data: any): Promise<FrappeResponse<FrappeDocType>> {
    const response: AxiosResponse<FrappeResponse<FrappeDocType>> = await this.client.put(
      `/api/resource/${doctype}/${name}`,
      data
    );
    return response.data;
  }

  async deleteDocTypeRecord(doctype: string, name: string): Promise<FrappeResponse> {
    const response: AxiosResponse<FrappeResponse> = await this.client.delete(
      `/api/resource/${doctype}/${name}`
    );
    return response.data;
  }

  // File upload
  async uploadFile(file: File, folder: string = 'Home'): Promise<FrappeResponse> {
    const formData = new FormData();
    formData.append('file', file);
    formData.append('folder', folder);
    formData.append('is_private', '0');

    const response: AxiosResponse<FrappeResponse> = await this.client.post(
      '/api/method/upload_file',
      formData,
      {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
      }
    );
    return response.data;
  }
}

// Export singleton instance
export const frappeAPI = new FrappeAPIClient();
export default frappeAPI;