const axios = require('axios');

const ACCEPT_HEADER = 'Application/vnd.pterodactyl.v1+json';

const defaultBaseUrl = () => process.env.PTERODACTYL_API_URL || 'https://panel.louismazin.ovh';
const defaultServerId = () => process.env.PTERODACTYL_SERVER_ID || 'ae4a628f';

const withAcceptHeader = (headers) => {
    // Keep existing headers behavior, but ensure we can talk to Pterodactyl v1.
    return {
        ...(headers || {}),
        Accept: headers?.Accept || ACCEPT_HEADER,
    };
};

const encodeQuery = (v) => encodeURIComponent(v);

async function listDirectory({ headers, baseUrl, serverId, directory }) {
    const url = `${baseUrl}/api/client/servers/${serverId}/files/list?directory=${encodeQuery(directory || '/')}`;
    const res = await axios.get(url, { headers: withAcceptHeader(headers) });
    const data = res?.data?.data || res?.data?.attributes?.data || res?.data?.data;

    // Standard response: { object:'list', data:[{object:'file_object', attributes:{...}}] }
    if (res?.data?.object === 'list' && Array.isArray(res?.data?.data)) {
        return res.data.data.map((x) => x.attributes);
    }

    // Fallback: try best-effort.
    if (Array.isArray(data)) return data;
    return [];
}

async function getDownloadUrl({ headers, baseUrl, serverId, file }) {
    const url = `${baseUrl}/api/client/servers/${serverId}/files/download?file=${encodeQuery(file)}`;

    // Most panels return JSON: { object:'signed_url', attributes:{ url } }
    const res = await axios.get(url, { headers: withAcceptHeader(headers), validateStatus: () => true });

    if (res.status >= 400) {
        const msg = typeof res.data === 'string' ? res.data : JSON.stringify(res.data);
        throw new Error(`Pterodactyl download URL failed (${res.status}): ${msg}`);
    }

    if (res.data && typeof res.data === 'object') {
        const signed =
            res.data?.attributes?.url ||
            res.data?.data?.attributes?.url ||
            res.data?.url;
        if (signed) return String(signed);
    }

    // Some installations may directly return the file, but in that case we don't have a URL.
    return null;
}

async function downloadFile({ headers, baseUrl, serverId, file }) {
    const signedUrl = await getDownloadUrl({ headers, baseUrl, serverId, file });

    if (signedUrl) {
        const res = await axios.get(signedUrl, {
            responseType: 'arraybuffer',
            maxRedirects: 5,
            validateStatus: () => true,
        });
        if (res.status >= 400) {
            throw new Error(`Signed download failed (${res.status}) for ${file}`);
        }
        return Buffer.from(res.data);
    }

    // Fallback attempt: direct download from API.
    const direct = `${baseUrl}/api/client/servers/${serverId}/files/download?file=${encodeQuery(file)}`;
    const res = await axios.get(direct, {
        headers: withAcceptHeader(headers),
        responseType: 'arraybuffer',
        maxRedirects: 5,
        validateStatus: () => true,
    });
    if (res.status >= 400) {
        throw new Error(`Direct download failed (${res.status}) for ${file}`);
    }
    return Buffer.from(res.data);
}

async function getUploadUrl({ headers, baseUrl, serverId, directory }) {
    const url = `${baseUrl}/api/client/servers/${serverId}/files/upload?directory=${encodeQuery(directory || '/')}`;
    const res = await axios.get(url, { headers: withAcceptHeader(headers) });
    const signed = res?.data?.attributes?.url || res?.data?.data?.attributes?.url;
    if (!signed) {
        throw new Error('Could not get signed upload URL from Pterodactyl');
    }
    return String(signed);
}

async function uploadSingleFile({ headers, baseUrl, serverId, directory, filename, content }) {
    const signed = await getUploadUrl({ headers, baseUrl, serverId, directory });

    // Use fetch + FormData (Node 18+) to match Pterodactyl upload behavior.
    const form = new FormData();
    const blob = new Blob([content]);
    form.append('files', blob, filename);

    const uploadUrl = `${signed}${signed.includes('?') ? '&' : '?'}directory=${encodeQuery(directory || '/')}`;

    const res = await fetch(uploadUrl, {
        method: 'POST',
        body: form,
    });

    if (!res.ok) {
        const text = await res.text().catch(() => '');
        throw new Error(`Upload failed (${res.status}): ${text}`);
    }
}

async function deleteFiles({ headers, baseUrl, serverId, root, files }) {
    const url = `${baseUrl}/api/client/servers/${serverId}/files/delete`;
    await axios.post(
        url,
        {
            root,
            files,
        },
        { headers: withAcceptHeader(headers) }
    );
}

module.exports = {
    defaultBaseUrl,
    defaultServerId,
    listDirectory,
    downloadFile,
    uploadSingleFile,
    deleteFiles,
};
