// TODO this is yet to be updated!

// Observables
import {Observable} from "zen-observable/lib/Observable";
import {merge, combineLatest, zip} from "zen-observable/lib/extras";

// Rollup and plugins
import * as rollup from 'rollup';

// Build configuration
import { CsxConfig, runArgs } from "./config";
import { logBundle } from "./log-bundle";

/**
 * Watch the CSX-sourcecode and rebuild as needed
 *
 * @param {CsxConfig} cfg - Configuration on how to build
 * @param {boolean} clean - Clean the dist-dir first
 * @returns {Promise<CsxConfig>}
 */
async function watch(cfg, clean) {
    
    let { src, dist, lib, sourceGlob, root } = cfg;
    
    // Clean host
    if (clean !== false) {
        await Promise.all([
            dist.remove('', {recursive: true}),
            lib.remove('', {recursive: true}),
        ]);
        console.log("Output-dirs cleaned!");
    }
    
    let discovered  = false;
    let appObservable = src.watch().glob(sourceGlob).map((event)=>{
        let updateStart = new Date();
        let deletedFiles = event.changes.filter(t=>t.event === 'removed').map(t=>t.file);
        let modifiedFiles = event.changes.filter(t=>t.event !== 'removed').map(t=>t.file);
    
        // somehow this runs twice now, TODO FIX PROPERLY!
        if(event.type==='discovery') {
            if (discovered) return;
            else discovered = true;
        }
    
        let targets = cfg.configureTargets(event.files);
    
        let builds = targets.map(async target=>{
            return {target, sources: await Promise.all(
                target.sources.map(async source=>{
                    let fileStart = new Date();
                    let bundle = await rollup.rollup(source.config);
                    let written = await bundle.write(source.config.output);
                    let stats = await root.stat(source.config.output.file);
                    logBundle(root.relative(source.config.output.file), (new Date()).getTime()-fileStart.getTime(), stats);
                    return {bundle, written, source, stats};
                })
            )};
        })
        
        return (async()=>{
            let results = await Promise.all(builds);
            return {
                files: event.files,
                duration: ((new Date()).getTime()-updateStart.getTime()),
                initialBuild: event.type==='discovery',
                results: results
            };
        })();
    });
    
    appObservable.subscribe( async (buildOp)=>{
        let {results, files, duration, initialBuild} = await buildOp;
        console.log(`[1;92mCSX ${initialBuild?'build':'updated'} in ${duration/1000}s: ${(new Date()).toUTCString()}[m`);
        
    });
    return appObservable;
}


// Execute self if script is run as entry (e.g. "node watch.js")
if (require.main === module) {
    // Run !
    watch(new CsxConfig({
        opts: { watch: true }
    })).then(
        (obs) => {
            obs.subscribe(() => {
                //console.log(`[1;92mServer updated: ${(new Date()).toUTCString()}[m`);
            })
        }
    );
}
