"use strict";

const fs      = require('fs');
const path    = require('path');
const console = require('gifer-console');

// Реальний transport: потоковий HTTP(S) download із progress/cancel.
function defaultTransport(url, dest, callbacks){
    var protocol = url.indexOf('https://') === 0 ? 'https' : 'http';
    var http     = require(protocol);
    var canceled = false;
    var request  = null;

    fs.open(dest, 'w', function(err, fd){
        if (err) return callbacks.error(err);

        var file = fs.createWriteStream(dest, { fd: fd });

        request = http.get(url, function(res){
            var total  = parseInt(res.headers['content-length'], 10) || 0;
            var loaded = 0;

            res.on('data', function(chunk){
                loaded += chunk.length;
                callbacks.progress({ loaded: loaded, total: total });
            });
            res.pipe(file);
            file.on('finish', function(){
                file.close(function(){
                    if (!canceled) callbacks.done(dest);
                });
            });
        });
        request.on('error', function(error){
            file.close();
            if (!canceled) callbacks.error(error);
        });
    });

    return {
        cancel: function(){
            canceled = true;
            if (request) request.destroy();
            try { fs.unlinkSync(dest); } catch (e) { /* файл міг не створитись */ }
        }
    };
}

function PluginDownload(opts){
    var paths     = opts.paths;
    var storage   = opts.storage;
    var emit      = opts.emitService;
    var transport = opts.transport || defaultTransport;

    var activeDownloads = {};

    function assertDownloadDest(id, dest){
        if (typeof dest !== 'string' || !dest.trim()){
            throw new Error('download destination is required');
        }

        var dataRoot = path.resolve(paths.pluginData(id));
        var tempRoot = path.resolve(storage.tempPath(id));
        var resolved = path.resolve(dest);

        if (resolved.indexOf(dataRoot + path.sep) !== 0 && resolved.indexOf(tempRoot + path.sep) !== 0){
            console.warn('[plugin:' + id + '] download dest escapes storage: ' + resolved, console.logLevel.WARN);
            throw new Error('download destination is outside plugin storage');
        }
        return resolved;
    }

    // node.log потрапляє в support-бандли, а URL завантаження регулярно несе креденшели —
    // presigned-підпис у query, API-ключ, userinfo. Лишаємо рівно те, що потрібно для
    // розбору інциденту: куди і за чим ходили.
    function safeUrl(raw){
        try {
            var parsed = new URL(raw);

            return parsed.origin + parsed.pathname;
        } catch (e) {
            return '<unparsable url>';
        }
    }

    function url(id, request){
        var dest = assertDownloadDest(id, request.dest);

        console.info('[plugin:' + id + '] download start ' + safeUrl(request.url), console.logLevel.INFO);

        var task = transport(request.url, dest, {
            progress: function(value){ emit(id, 'svc.download.progress', { id: request.id, value: value }); },
            done    : function(file){
                delete activeDownloads[request.id];
                emit(id, 'svc.download.done', { id: request.id, path: file });
            },
            error   : function(error){
                delete activeDownloads[request.id];
                console.warn('[plugin:' + id + '] download error: ' + error.message, console.logLevel.WARN);
                emit(id, 'svc.download.error', { id: request.id, error: error.message });
            }
        });

        activeDownloads[request.id] = { pluginId: id, cancel: task.cancel };
        return { id: request.id };
    }

    function serverFile(id, request){
        void id; void request;
        // потребує затвердженого server contract (Phase 5): metadata файла видає СЕРВЕР
        throw new Error('download.serverFile requires server contract');
    }

    function cancel(id, taskId){
        var task = activeDownloads[taskId];

        if (!task || task.pluginId !== id) throw new Error('unknown download task');
        task.cancel();
        delete activeDownloads[taskId];
        console.info('[plugin:' + id + '] download canceled', console.logLevel.INFO);
    }

    this.url        = url;
    this.serverFile = serverFile;
    this.cancel     = cancel;
}

module.exports = PluginDownload;
