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

class ApiClient {
    private client: AxiosInstance

    constructor() {
        this.client = axios.create({
            withCredentials: true,
            headers: {
                'Content-Type': 'application/json',
            },
        })
    }

    private getCsrfToken(): string {
        let cookieValue = ''
        if (document.cookie && document.cookie !== '') {
            const cookies = document.cookie.split(';')
            for (const rawCookie of cookies) {
                const cookie = (rawCookie || '').trim()
                if (cookie.startsWith('csrftoken=')) {
                    cookieValue = decodeURIComponent(cookie.slice('csrftoken='.length))
                    break
                }
            }
        }
        return cookieValue
    }

    private withCsrf(config?: AxiosRequestConfig): AxiosRequestConfig {
        const token = this.getCsrfToken()
        const csrfHeader = token ? { 'X-CSRFToken': token } : {}
        return {
            ...config,
            headers: {
                ...csrfHeader,
                ...(config?.headers || {}),
            },
        }
    }

    processUrl(endpoint: string): string {
        return `${apiEndpoint}${endpoint}`
    }

    get<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
        return this.client.get<T>(this.processUrl(url), this.withCsrf(config))
    }

    post<T = unknown>(
        url: string,
        data?: unknown,
        config?: AxiosRequestConfig,
    ): Promise<AxiosResponse<T>> {
        return this.client.post<T>(this.processUrl(url), data, this.withCsrf(config))
    }

    put<T = unknown>(
        url: string,
        data?: unknown,
        config?: AxiosRequestConfig,
    ): Promise<AxiosResponse<T>> {
        return this.client.put<T>(this.processUrl(url), data, this.withCsrf(config))
    }

    patch<T = unknown>(
        url: string,
        data?: unknown,
        config?: AxiosRequestConfig,
    ): Promise<AxiosResponse<T>> {
        return this.client.patch<T>(this.processUrl(url), data, this.withCsrf(config))
    }

    delete<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
        return this.client.delete<T>(this.processUrl(url), this.withCsrf(config))
    }
}

export const apiEndpoint = '/api/';

export const API = {
    auth: {
        me: () => 'user/me/',
        login: () => 'user/login/',
        logout: () => 'user/logout/',
        session: () => 'user/session/',
        signup: () => 'user/signup/',
        changePassword: () => 'user/change_password/',
    },

    organization: {
        list: () => 'organization/',
        byId: (uuid: string) => `organization/${uuid}/`,
        members: {
            list: (organizationUuid: string) => `organization/${organizationUuid}/members/`,
            remove: (organizationUuid: string, userUuid: string) =>
                `organization/${organizationUuid}/member/${userUuid}/remove/`,
        },
        leave: (uuid: string) => `organization/${uuid}/leave/`,
    },

    invites: {
        list: (organizationUuid: string) => `invite/?organization_uuid=${organizationUuid}`,
        create: (organizationUuid: string, maxUses: number) =>
            `invite/?organization_uuid=${organizationUuid}&max_uses=${maxUses}`,
        revoke: (organizationUuid: string, inviteUuid: string) =>
            `invite/${inviteUuid}/?organization_uuid=${organizationUuid}`,
        join: (inviteUuid: string) => `invite/join/?invite_uuid=${inviteUuid}`,
    },

    roles: {
        list: (organizationUuid: string) => `role/?organization_uuid=${organizationUuid}`,
        mine: () => 'role/mine/',
        remove: (organizationUuid: string, roleUuid: string) =>
            `role/${roleUuid}/?organization_uuid=${organizationUuid}`,
        join: (organizationUuid: string, roleUuid: string) =>
            `role/${roleUuid}/join/?organization_uuid=${organizationUuid}`,
    },

    knowledge: {
        trainingFiles: {
            list: () => 'training-file/',
            byId: (uuid: string) => `training-file/${uuid}/`,
            retry: (uuid: string) => `training-file/${uuid}/retry/`,
        },
        roleRagDocuments: {
            list: () => 'role-rag-document/',
            byId: (uuid: string) => `role-rag-document/${uuid}/`,
        },
    },

    agents: {
        configs: {
            list: () => 'agent-config/',
            byId: (uuid: string) => `agent-config/${uuid}/`,
        },
    },

    onboarding: {
        flows: {
            list: () => 'onboarding-flow/',
            byId: (uuid: string) => `onboarding-flow/${uuid}/`,
            startSession: (uuid: string) => `onboarding-flow/${uuid}/start-session/`,
        },
        sessions: {
            list: () => 'onboarding-session/',
            progressOverview: () => 'onboarding-session/progress-overview/',
            byId: (uuid: string) => `onboarding-session/${uuid}/`,
            interact: (uuid: string) => `onboarding-session/${uuid}/interact/`,
            history: (uuid: string) => `onboarding-session/${uuid}/history/`,
            complete: (uuid: string) => `onboarding-session/${uuid}/complete/`,
        },
        logs: {
            list: () => 'agent-interaction-log/',
            byId: (uuid: string) => `agent-interaction-log/${uuid}/`,
        },
    },
}
export const apiClient = new ApiClient()
export { isAxiosError } from 'axios'
