import Keychain from './keychain';
import { downloadStream } from './api';

let noSave = false;
const map = new Map();

self.addEventListener('install', event => {
  self.skipWaiting();
});

self.addEventListener('activate', event => {
  self.clients.claim();
});

async function decryptStream(request) {
  const id = request.url.split('/')[5];
  try {
    const file = map.get(id);

    file.download = downloadStream(id, file.keychain);

    const stream = await file.download.result;

    // eslint-disable-next-line no-undef
    const progStream = new TransformStream({
      transform: (chunk, controller) => {
        file.progress += chunk.length;
        controller.enqueue(chunk);
      }
    });

    const readStream = stream.pipeThrough(progStream);
    const decrypted = file.keychain.decryptStream(readStream);

    const headers = {
      'Content-Disposition': 'attachment; filename=' + file.filename
    };

    return new Response(decrypted, { headers });
  } catch (e) {
    if (noSave) {
      return new Response(null, { status: e.message });
    }

    const redirectRes = await fetch(`/download/${id}`);
    return new Response(redirectRes.body, { status: 302 });
  }
}

self.onfetch = event => {
  const req = event.request.clone();
  if (req.url.includes('/api/download')) {
    event.respondWith(decryptStream(req));
  }
};

self.onmessage = event => {
  if (event.data.request === 'init') {
    noSave = event.data.noSave;
    const info = {
      keychain: new Keychain(event.data.key),
      filename: event.data.filename,
      progress: 0,
      cancelled: false
    };
    if (event.data.requiresPassword) {
      info.keychain.setPassword(event.data.password, event.data.url);
    }
    map.set(event.data.id, info);

    event.ports[0].postMessage('file info received');
  } else if (event.data.request === 'progress') {
    const file = map.get(event.data.id);
    if (file.cancelled) {
      event.ports[0].postMessage({ error: 'cancelled' });
    } else {
      event.ports[0].postMessage({ progress: file.progress });
    }
  } else if (event.data.request === 'cancel') {
    const file = map.get(event.data.id);
    file.cancelled = true;
    if (file.download) {
      file.download.cancel();
    }
    event.ports[0].postMessage('download cancelled');
  }
};