import axios from 'axios';
import { boot, withFilters } from './format';

/*
 * Same-origin JSON client. The session cookie authenticates, the CSRF token from
 * the shell's <meta> tag satisfies Laravel's VerifyCsrfToken, and Accept: json
 * makes validation failures come back as 422 payloads instead of redirects.
 */
const http = axios.create({
    headers: {
        Accept: 'application/json',
        'X-Requested-With': 'XMLHttpRequest',
        'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.content ?? '',
    },
});

/** Logging in and out regenerates the session, and with it the CSRF token. */
export function setCsrfToken(token) {
    if (token) http.defaults.headers['X-CSRF-TOKEN'] = token;
}

/** A failed request, already reduced to what the UI shows. */
export class ApiError extends Error {
    constructor(message, { errors = {}, status = 0 } = {}) {
        super(message);
        this.name = 'ApiError';
        this.errors = errors;
        this.status = status;
    }

    get isValidation() {
        return this.status === 422;
    }
}

function toApiError(error) {
    const status = error.response?.status ?? 0;
    const data = error.response?.data ?? {};

    if (status === 422) {
        return new ApiError(data.message || 'দেওয়া তথ্যে সমস্যা আছে।', { errors: data.errors ?? {}, status });
    }

    if (status === 401) {
        return new ApiError('আবার লগইন করতে হবে।', { status });
    }

    if (status === 403) {
        return new ApiError('এই কাজের অনুমতি আপনার নেই।', { status });
    }

    if (status === 404) {
        return new ApiError('এন্ট্রিটি আর নেই — সম্ভবত অন্য কোথাও মুছে ফেলা হয়েছে।', { status });
    }

    if (status === 429) {
        return new ApiError('অনেকবার চেষ্টা করা হয়েছে — একটু পরে আবার দেখুন।', { status });
    }

    if (status === 419) {
        return new ApiError('সেশনের সময় শেষ। পেজটি রিফ্রেশ করে আবার চেষ্টা করুন।', { status });
    }

    if (status >= 500) {
        return new ApiError('সার্ভারে সমস্যা হয়েছে। আবার চেষ্টা করুন।', { status });
    }

    if (!error.response) {
        return new ApiError('সার্ভারে পৌঁছানো যাচ্ছে না — ইন্টারনেট সংযোগ দেখুন।', { status });
    }

    return new ApiError(data.message || 'অজানা সমস্যা হয়েছে।', { status });
}

async function request(method, url, data) {
    try {
        const response = await http.request({ method, url, data });

        return response.data;
    } catch (error) {
        throw toApiError(error);
    }
}

const routes = boot.routes ?? {};
const endpoint = routes.expenses ?? '/api/expenses';

/*
 * Writes carry the active filters too: the server answers every call with the
 * recalculated list for that view, so one round trip both saves and refreshes.
 */
export const api = {
    list: (filters) => request('get', withFilters(endpoint, filters)),
    create: (payload, filters) => request('post', withFilters(endpoint, filters), payload),
    update: (id, payload, filters) => request('put', withFilters(`${endpoint}/${id}`, filters), payload),
    remove: (id, filters) => request('delete', withFilters(`${endpoint}/${id}`, filters)),

    login: (credentials) => request('post', routes.login ?? '/api/login', credentials),
    logout: () => request('post', routes.logout ?? '/api/logout'),
};
