let dark = document.location.search.includes('dark-theme=true');

if (dark)
    document.body.classList.add('dark-theme');


var COLORS = dark ?
    ['#FF0000', '#00FF00', '#0000FF', '#FF00FF', '#FFFF00', '#0000FF', '#F090F0', '#90F0F0', '#F0F090'] :
    ['#CC0000', '#00CC00', '#0000CC', '#CC00CC', '#CCCC00', '#0000CC', '#C060C0', '#60C0C0', '#C0C060']

const load = () => {
    const l0 = document.createElement('div')
    const l1 = document.createElement('div')
    const l2 = document.createElement('div')
    l0.classList.add('lds-ripple')

    l0.appendChild(l1)
    l0.appendChild(l2)
    return l0
}

const getCheckedOptions = () => {
    const options = Array.from(document.querySelectorAll('.option-div'))
        .map(e => Array.from(e.children)
        .filter(e => e.nodeName == 'DIV'))
        .filter(e => e.length)
        .flat()
        .map(e => e.id)
        .filter(e => document.querySelector(`#${e}-checkbox`).checked)

    const optionsDict = {}
    for (let option of options) {
        const key = option.split('-option-')[0]
        const value = option.split('-option-')[1]

        if (key in optionsDict)
            optionsDict[key].push(value)
        else
            optionsDict[key] = [value]
    }

    return optionsDict;
}

const addOption = (category, optionName) => {
    /* Options for the issue div */
    const issueDiv = document.getElementById(`${category}Div`);
    const div = document.createElement('div')

    let found = false;
    let optionNumber = 0;
    while (!found && ++optionNumber < 100) {
        let previousOption = document.getElementById(`${category}-option-${optionNumber}`);
        found = previousOption === null;
    }

    div.id = `${category}-option-${optionNumber}`;
    issueDiv.appendChild(div);

    const checkBox = document.createElement('input');
    checkBox.type = 'checkbox'
    checkBox.id = `${category}-option-${optionNumber}-checkbox`

    const checkBoxLabel = document.createElement('label');
    const labelSpan = document.createElement('span')
    labelSpan.textContent = optionName;
    checkBoxLabel.appendChild(checkBox)
    checkBoxLabel.appendChild(labelSpan)
    div.appendChild(checkBoxLabel)

    return optionNumber
}

let charts = [];

const createButton = (title, libraries, methods) => {
    const button = document.createElement('button')
    button.textContent = title;
    button.onclick = async () => {
        document.getElementById('pip-graph').innerHTML = ''
        document.getElementById('star-graph').innerHTML = ''
        document.getElementById('issue-graph').innerHTML = ''
        const e = load()
        document.body.appendChild(e)
        const selectedInternalLibraries = libraries.internal.filter(e => document.querySelector(`#${e}Checkbox`).checked);
        const selectedExternalLibraries = libraries.external.filter(e => document.querySelector(`#${e}Checkbox`).checked);
        const selectedLibraries = selectedInternalLibraries.concat(selectedExternalLibraries);

        const relevantOptions = getCheckedOptions();

        if (charts.length !== 0) {
            for (const chart of charts) {
                chart.destroy()
            }
        }
        for (const method of methods()) {
            charts.push(await method(selectedLibraries, relevantOptions))
        }
        document.body.removeChild(e)
    };

    return button;
}

const initialize = async () => {
    const inferResponse = await fetch(`initialize`);
    console.log(inferResponse);
    const inferJson = await inferResponse.json();
    console.log(inferJson);

    const warnings = document.getElementById("warnings")
    const librarySelector = document.getElementById('library-selector');
    const graphSelector = document.getElementById('graph-selector');
    const selectorSubmit = document.getElementById('selector-submit');

    const introSpan = document.createElement("h3")
    introSpan.textContent = "Select libraries to display"
    librarySelector.appendChild(introSpan);

    const graphSpan = document.createElement("h3")
    graphSpan.textContent = "Select graphs to display"
    graphSelector.appendChild(graphSpan);

    if (inferJson.warnings.length > 0) {
        for (const warning of inferJson.warnings) {
            const div = document.createElement('div');
            div.classList.add('warning-div')

            const labelSpan = document.createElement('span');
            labelSpan.textContent = `Warning: ${warning}`;

            div.appendChild(labelSpan);
            warnings.appendChild(div);
        }
    }

    for (const element of inferJson.internal) {
        const div = document.createElement('div');
        const checkBox = document.createElement('input');
        checkBox.type = 'checkbox'
        checkBox.id = `${element}Checkbox`;

        const checkBoxLabel = document.createElement('label');
        const labelSpan = document.createElement('span')

        labelSpan.textContent = element.charAt(0).toUpperCase() + element.slice(1)
        checkBoxLabel.appendChild(checkBox)
        checkBoxLabel.appendChild(labelSpan)

        div.appendChild(checkBoxLabel)
        librarySelector.appendChild(div)
    }

    const externalLibs = document.createElement("h3")
    externalLibs.textContent = "External Libraries"
    librarySelector.appendChild(externalLibs);

    for (const element of inferJson.external) {
        const div = document.createElement('div');
        const checkBox = document.createElement('input');
        checkBox.type = 'checkbox'
        checkBox.id = `${element}Checkbox`;

        const checkBoxLabel = document.createElement('label');
        const labelSpan = document.createElement('span')

        labelSpan.textContent = element.charAt(0).toUpperCase() + element.slice(1)
        checkBoxLabel.appendChild(checkBox)
        checkBoxLabel.appendChild(labelSpan)

        div.appendChild(checkBoxLabel)
        librarySelector.appendChild(div)
    }

    for (const element of ['pip', 'stars', 'issue']) {
        const div = document.createElement('div');
        div.classList.add('option-div')
        div.id = `${element}Div`;

        const checkBox = document.createElement('input');
        checkBox.type = 'checkbox'
        checkBox.id = `${element}CheckboxGraph`;

        const checkBoxLabel = document.createElement('label');
        const labelSpan = document.createElement('span')
        labelSpan.textContent = element.charAt(0).toUpperCase() + element.slice(1)
        checkBoxLabel.appendChild(checkBox)
        checkBoxLabel.appendChild(labelSpan)

        div.appendChild(checkBoxLabel)
        graphSelector.appendChild(div)
    }

    addOption('pip', "Cumulated");
    addOption('pip', "Week over week");

    addOption('issue', "Exclude org members");
    addOption('issue', "Week over week");
    addOption('issue', "Cumulated");

    addOption('stars', "Week over week");
    addOption('stars', "Cumulated");

    const fetchButton = createButton('Fetch', inferJson, () => {
        const graphNames = ['pip', 'stars', 'issue'].filter(e => document.querySelector(`#${e}CheckboxGraph`).checked);
        const graphs = []

        if (graphNames.includes('pip'))
            graphs.push(retrievePipInstalls)

        if (graphNames.includes('stars'))
            graphs.push(retrieveStars)

        if (graphNames.includes('issue'))
            graphs.push(retrieveIssues)

        return graphs
    })
    selectorSubmit.appendChild(fetchButton);
};

const retrievePipInstalls = async (libraryNames, options) => {
    const relevantOptions = options['pip']
    const inferResponse = await fetch(`retrievePipInstalls?input=${libraryNames}&options=${relevantOptions}`);
    const inferJson = await inferResponse.json();
    const colors = [...COLORS];

    const labels = Array.from(inferJson['day']).map(e => new Date(e))
    const datasets = [];
    for (const element in inferJson) {
        if (element === 'day')
            continue

        const color = colors.pop()
        datasets.push({
            label: element,
            data: inferJson[element],
            backgroundColor: color,
            borderColor: color,
            tension: 0.01,
            pointRadius: 1,
            borderWidth: 2,
            fill: false
        })
    }

    const ctx = document.getElementById('pip-graph');

    const myChart = new Chart(ctx, {
        type: 'line',
        data: {labels, datasets},
        options: {
            scales: {
                y: {
                    beginAtZero: true
                },
                x: {
                    type: 'time',
                }
            },
            plugins: {
                title: {
                    display: true,
                    text: 'Pip installs'
                }
            }
        }
    });
    return myChart;
};

const retrieveStars = async (libraryNames, options) => {
    const relevantOptions = options['stars']
    const inferResponse = await fetch(`retrieveStars?input=${libraryNames}&options=${relevantOptions}`);
    const inferJson = await inferResponse.json();
    const colors = [...COLORS];

    const labels = Array.from(inferJson['day']).map(e => new Date(e))
    const datasets = [];
    for (const element in inferJson) {
        if (element === 'day')
            continue

        const color = colors.pop()
        datasets.push({
            label: element,
            data: inferJson[element],
            backgroundColor: color,
            borderColor: color,
            tension: 0.01,
            pointRadius: 1,
            borderWidth: 2,
            fill: false
        })
    }

    const ctx = document.getElementById('star-graph');

    const myChart = new Chart(ctx, {
        title: "Stars",
        type: 'line',
        data: {labels, datasets},
        options: {
            scales: {
                y: {
                    beginAtZero: true
                },
                x: {
                    type: 'time',
                }
            },
            plugins: {
                title: {
                    display: true,
                    text: 'Number of stargazers'
                }
            }
        }
    });
    return myChart;
};

const retrieveIssues = async (libraryNames, options) => {
    const relevantOptions = options['issue']
    const inferResponse = await fetch(`retrieveIssues?input=${libraryNames}&options=${relevantOptions}`);
    const inferJson = await inferResponse.json();
    const colors = [...COLORS];

    const labels = Array.from(inferJson['day']).map(e => new Date(e))
    const datasets = [];
    for (const element in inferJson) {
        if (element === 'day')
            continue

        const color = colors.pop()
        datasets.push({
            label: element,
            data: inferJson[element],
            backgroundColor: color,
            borderColor: color,
            tension: 0.01,
            pointRadius: 1,
            borderWidth: 2,
            fill: false
        })
    }

    const ctx = document.getElementById('issue-graph');

    const myChart = new Chart(ctx, {
        title: "Issues",
        type: 'line',
        data: {labels, datasets},
        options: {
            scales: {
                y: {
                    beginAtZero: true
                },
                x: {
                    type: 'time',
                }
            },
            plugins: {
                title: {
                    display: true,
                    text: 'Cumulated number of issues, PRs, and comments'
                }
            }
        }
    });
    return myChart;
};

(
    async () => {
        const e = load()
        document.body.appendChild(e)
        await initialize()
        document.body.removeChild(e)
    }
)();