'use strict';
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
import { ConnectionProvider, ConnectionNode } from './connections'
import { TextDocumentContentProvider } from './resultsetview'
import { BlockDetector } from './editorsupport'

const { spawn } = require('child_process');
const extensionName = "frog";

let currentConnection : ConnectionNode = null;
let dbSession = null;


// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
    let previewUri = vscode.Uri.parse('frog-view://authority/resultset');

    let statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
    statusBarItem.text = 'Frog: No connection'
    statusBarItem.show()
    context.subscriptions.push(statusBarItem);

    const connectionProvider = new ConnectionProvider();
    let myOutputChannel = vscode.window.createOutputChannel('SQL Query Results');
    context.subscriptions.push(myOutputChannel);

    let diagnosticCollection = vscode.languages.createDiagnosticCollection(extensionName);
    context.subscriptions.push(diagnosticCollection);

    vscode.window.registerTreeDataProvider('connections', connectionProvider);

    let provider = new TextDocumentContentProvider();
	let registration = vscode.workspace.registerTextDocumentContentProvider('frog-view', provider);

        // Use the console to output diagnostic information (console.log) and errors (console.error)
    // This line of code will only be executed once when your extension is activated
    console.log('Congratulations, your extension "frog" is now active!');

    let disposable = vscode.commands.registerCommand('frog.executeSnippet', () => {
        // The code you place here will be executed every time your command is executed
        
        let editor = vscode.window.activeTextEditor;

        if (!editor) return;

        let selection = editor.selection;

        if (selection.isEmpty) {
            new BlockDetector(editor).detect();
        }

        let text = editor.document.getText(editor.selection);        

        if (!dbSession) {
            if (!currentConnection) {
                vscode.window.showWarningMessage('No connection selected');
                return;
            }

            let extPath = vscode.extensions.getExtension("todie.frog").extensionPath;
            dbSession = spawn("java", ['-jar', extPath + '/frog-runner.jar', currentConnection.host, currentConnection.port, currentConnection.schema, currentConnection.username, currentConnection.password]);

            let outputBuffer = "";

            dbSession.stdout.on('data', (data) => {
                outputBuffer += data.toString();
                
                try {
                    let json = JSON.parse(outputBuffer);

                    //console.log(json);

                    const diagnostics = [];
                    let cd = json['columnDefinitions']

                    if (!json['rows']) {
                        if ('dbOutput' in json) {
                            myOutputChannel.append(json['dbOutput'].map((x) => `DB: ${x}\n`).join(''));
                        }
                        if (json['userErrors']) {
                            myOutputChannel.append("Errors found:\n");

                            const document = vscode.window.activeTextEditor.document;
                            
                            for (let error of json['userErrors'][0]['lines']) {
                                let range = document.lineAt(selection.start.line + error['line'] - 1).range;
                                let diagnostic = new vscode.Diagnostic(range, error['text'], vscode.DiagnosticSeverity.Error);
                                diagnostic.source = extensionName;
                                diagnostic.code = "code";
                                diagnostics.push(diagnostic);
                                myOutputChannel.append(error['line'] + ": " + error['text'] + "\n");
                            }

                            diagnosticCollection.set(document.uri, diagnostics);
                        } else if (json['exception']) {
                            myOutputChannel.append("Exception caught: " + json['exceptionMessage'] + "\n");
                        } else if ("affectedRows" in json) {
                            myOutputChannel.append(json['affectedRows'] + " rows affected.\n");
                        } else {
                            myOutputChannel.append("SQL executed successfully.\n");
                        }
                    } else {
                        provider.setData(json);
                        provider.update(previewUri);

                        vscode.commands.executeCommand('vscode.previewHtml', previewUri, vscode.ViewColumn.Two, 'Result Set View').then((success) => {
                        }, (reason) => {
                            vscode.window.showErrorMessage(reason);
                        });
                
                        myOutputChannel.append("Query successful.\n");
                    }

                    myOutputChannel.append("-- " + new Date() + " -------------------------------\n");
                    outputBuffer = "";
                    statusBarItem.text = currentConnection.name + " (Connected)";
                } catch (e) {
                    console.log(e);
                }
                statusBarItem.text = currentConnection.name + " (Connected)";
            });
              
            dbSession.stderr.on('data', (data) => {
                myOutputChannel.show(true);
                myOutputChannel.append(data.toString());
            });

            dbSession.on('close', (code) => {
                console.log(`child process exited with code ${code}`);
                dbSession = null;
            });
        }

        if (!text) {
            vscode.window.showInformationMessage('No text selected');
            return;
        }

        
        myOutputChannel.append("-- " + new Date() + " -------------------------------\n"); //Executing: '" + text + "'\n");
        let input = { "sql": text, "rowLimit": 30 };
        dbSession.stdin.write(JSON.stringify(input) + "\n--- END ---\n");
        statusBarItem.text = currentConnection.name + " (Connected, Query running...)";
    });

    context.subscriptions.push(disposable, registration);

    function changeSession(node: ConnectionNode) {
        currentConnection = node;
        statusBarItem.text = node.name;
        if (dbSession) {
            dbSession.stdin.end();
            dbSession = null;
        }
    }

    vscode.commands.registerCommand('selectConnection', (node: ConnectionNode) => {
        if (!dbSession) {
            changeSession(node)
        } else {
            vscode.window.showInformationMessage(`You want to change the connection to '${node.name}'. Sure?`, 'Yes')
            .then( (selection) => {
                if (selection == 'Yes') {
                    changeSession(node);
                }
            }, (reason) => {})
        }
	})
}

// this method is called when your extension is deactivated
export function deactivate() {
    if (dbSession) dbSession.stdin.end();
}