const fs = require('fs');
const path = require('path');

const normalizeUrl = (url) => String(url || '').trim().replace(/\/+$/, '');

const buildModelUploadForm = ({ modelId, modelPath, mtlPath, texturePath, extraFields = {} }) => {
    if (!modelPath) {
        throw new Error('modelPath is required for upload');
    }

    const resolvedModelPath = path.resolve(modelPath);
    if (!fs.existsSync(resolvedModelPath)) {
        throw new Error(`Model file not found: ${resolvedModelPath}`);
    }

    const form = new FormData();
    if (modelId) {
        form.append('modelId', String(modelId));
    }

    form.append('modelFile', fs.createReadStream(resolvedModelPath), path.basename(resolvedModelPath));

    if (mtlPath) {
        const resolvedMtlPath = path.resolve(mtlPath);
        if (!fs.existsSync(resolvedMtlPath)) {
            throw new Error(`MTL file not found: ${resolvedMtlPath}`);
        }
        form.append('mtlFile', fs.createReadStream(resolvedMtlPath), path.basename(resolvedMtlPath));
    }

    if (texturePath) {
        const resolvedTexturePath = path.resolve(texturePath);
        if (!fs.existsSync(resolvedTexturePath)) {
            throw new Error(`Texture file not found: ${resolvedTexturePath}`);
        }
        form.append('textureFile', fs.createReadStream(resolvedTexturePath), path.basename(resolvedTexturePath));
    }

    Object.entries(extraFields).forEach(([key, value]) => {
        if (value !== undefined && value !== null) {
            form.append(key, String(value));
        }
    });

    return form;
};

const uploadModelFiles = async ({ serverUrl = 'http://localhost:3002', modelId, modelPath, mtlPath, texturePath, extraFields = {} }) => {
    const normalizedUrl = normalizeUrl(serverUrl);
    const endpoint = `${normalizedUrl}/api/models`;
    const form = buildModelUploadForm({ modelId, modelPath, mtlPath, texturePath, extraFields });

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

    const result = await response.json().catch(() => ({ error: 'invalid_json_response' }));
    if (!response.ok) {
        const message = result?.message || result?.error || `Upload failed with HTTP ${response.status}`;
        const error = new Error(message);
        error.status = response.status;
        error.response = result;
        throw error;
    }

    return result;
};

const printUsage = () => {
    console.log('Usage: node modelUploadClient.js --server http://localhost:3002 --model ./file.obj --mtl ./file.mtl --texture ./file.png');
};

const runCli = async () => {
    const args = process.argv.slice(2);
    const params = {};

    for (let i = 0; i < args.length; i += 2) {
        const key = args[i];
        const value = args[i + 1];
        if (!value) break;

        switch (key) {
            case '--server':
                params.serverUrl = value;
                break;
            case '--model':
                params.modelPath = value;
                break;
            case '--mtl':
                params.mtlPath = value;
                break;
            case '--texture':
                params.texturePath = value;
                break;
            default:
                console.warn(`Unknown option: ${key}`);
                break;
        }
    }

    if (!params.modelPath || !params.mtlPath || !params.texturePath) {
        printUsage();
        process.exit(1);
    }

    try {
        const result = await uploadModelFiles(params);
        console.log('Upload successful:', JSON.stringify(result, null, 2));
    } catch (error) {
        console.error('Upload failed:', error.message || error);
        if (error.response) {
            console.error('Server response:', JSON.stringify(error.response, null, 2));
        }
        process.exit(1);
    }
};

module.exports = {
    uploadModelFiles,
    buildModelUploadForm,
};

if (require.main === module) {
    runCli();
}
