import axios, { AxiosRequestConfig, AxiosResponse, AxiosError, Method } from 'axios';
import UnableToProceed from '../../shared/exceptions/UnableToProceed';
import Unauthorized from '../../shared/exceptions/Unauthorized';

// Allowed HTTP methods for external Canvas API requests
const ALLOWED_METHODS: Method[] = ['GET']; // Expand this list in the future as needed

class CanvasGraphqlApi {
    private static readonly baseURL: string = process.env.CANVAS_API_URL || 'https://canvas.instructure.com/api/graphql';
    private static readonly accessToken: string = process.env.CANVAS_API_KEY || '';

    public static async doGraphqlRequest<T>(
        query: string,
        variables?: Record<string, any>,
        headersExtra?: Record<string, string>,
        method: Method = 'GET'
    ): Promise<T> {
        if (!ALLOWED_METHODS.includes(method)) {
            throw new UnableToProceed(`HTTP method ${method} is not allowed for external Canvas API requests.`);
        }

        const headers = {
            Authorization: `Bearer ${CanvasGraphqlApi.accessToken}`,
            'Content-Type': 'application/json',
            ...headersExtra,
        };

        const requestBody = {
            query,
            variables: variables || {},
        };

        const config: AxiosRequestConfig = {
            method,
            url: CanvasGraphqlApi.baseURL,
            headers,
            data: requestBody,
        };

        console.log(`Sending request to Canvas GraphQL: ${config.url}`);
        console.log('Request Headers:', headers);
        console.log('Request Body:', JSON.stringify(requestBody, null, 2));

        try {
            const response: AxiosResponse<T> = await axios(config);
            console.log('Received response from Canvas:', JSON.stringify(response.data, null, 2));
            return response.data;
        } catch (error: unknown) {
            const axiosError = error as AxiosError;
            console.error(`Error from Canvas GraphQL request:`, axiosError);
            if (axiosError.response) {
                console.error('Response Data:', JSON.stringify(axiosError.response.data, null, 2));
                if (axiosError.response.status === 401) {
                    throw new Unauthorized('Unauthorized access');
                }
                throw new UnableToProceed(
                    `HTTP ${axiosError.response.status} error at Canvas GraphQL: ${JSON.stringify(axiosError.response.data, null, 2)}`
                );
            } else if (axiosError.request) {
                console.error('No response received from Canvas');
                throw new UnableToProceed('No response from server');
            } else {
                console.error('Unexpected error:', axiosError.message);
                throw new UnableToProceed(axiosError.message);
            }
        }
    }
}

export default CanvasGraphqlApi; 