const fetch = require('node-fetch');
const {resolve} = require('path');
const fs = require('fs');
const clc = require('cli-color');
const {v4: uuidv4} = require('uuid');

const getWidgets = async (uStoreServerUrl, url, cultureCode) => {
    const res = await fetch(`${uStoreServerUrl.startsWith('http') ? '' : 'http://'}${uStoreServerUrl}/uStoreRestAPI/v1/store/resourceByUrl?url=${url}&type=6&cultureCode=${cultureCode}&isDraft=false`)
    return res.text()
}

const getWidgetsConfiguration = async (uStoreServerUrl, id) => {
    const res = await fetch(`${uStoreServerUrl.startsWith('http') ? '' : 'http://'}${uStoreServerUrl}/uStoreThemeCustomizations/${id}/Published/Widgets/widgetConfig.js`)
    return res.text()
}

const getDevJsonWidgetsConfig = (argv) => {
    const jsonArgv = argv('json')
    let config = {}
    const jsonPath = jsonArgv
    if (jsonPath) {
        const jsonPathResolved = resolve('../widgets', jsonPath)
        if (fs.existsSync(jsonPathResolved)) {
            config = JSON.parse(fs.readFileSync(jsonPathResolved, 'utf8'))
        } else {
            console.log(clc.red(`File ${jsonPathResolved} not found`))
        }
    }

    return config
}

const getDevParamsWidgetsConfig = (argv, widgetNames) => widgetNames.reduce((acc, widgetName) => {
    if (argv(widgetName)) {
        return {
            ...acc,
            [widgetName]: argv(widgetName)
        }
    } else {
        return acc
    }
}, {})

/**
 * Get widgets config from json file and/or command line params
 * If json config exists, it will take location config from there
 * If cli params exist together with json file, cli params will override json config
 * If no json config, cli params must be provided
 */
const getDevWidgetsConfig = async (argv, widgetNames) => {
    try {
        const jsonWidgetConfig = getDevJsonWidgetsConfig(argv)
        if (Object.keys(jsonWidgetConfig).length) {
            const widgetNames = Object.keys(jsonWidgetConfig)
            return {...jsonWidgetConfig, ...getDevParamsWidgetsConfig(argv, widgetNames)}
        } else {
            return getDevParamsWidgetsConfig(argv, widgetNames)
        }
    } catch (e) {
        console.log(clc.red(e))
    }
}

const getLocalWidgetsConfig = (localWidgetsDirs) => localWidgetsDirs.map((localWidgetsDir) => {
    if (!fs.existsSync(resolve('../widgets', localWidgetsDir))) {
        console.log(clc.red(`File ${localWidgetsDir} not found`))
        process.exit(1)
        return null
    }
    const localWidgetsConfig = fs.readFileSync(resolve('../widgets', localWidgetsDir), 'utf8')
    return JSON.parse(localWidgetsConfig)
})

const getLocalDevWidgetIds = (localDevWidgetsList) => {
    const localWidgetsIds = new Map()
    localDevWidgetsList.forEach(widget => {
        localWidgetsIds.set(widget, uuidv4())
    })
    return localWidgetsIds
}

const getWidgetsConfig = async (argv, uStoreServerUrl, localWidgetsDirs, localWidgetsList, localWidgetsIds, url, cultureCode) => {
    const widgetsRemoteConfig = await getWidgets(uStoreServerUrl, url, cultureCode) // get widgets config from uStore server as text
    const widgetsRemoteConfigJson = JSON.parse(widgetsRemoteConfig.replace('var xmpie_uStore_widgets = ', '')) // parse widgets config from uStore server as json
    const localWidgetsLocationConfig = await getDevWidgetsConfig(argv, localWidgetsList)
    const localWidgetsConfig = getLocalWidgetsConfig(localWidgetsDirs)
    const remoteWidgetsList = widgetsRemoteConfigJson.definitions.map(widget => widget.name)
    const fullWidgetsList = [...new Set([...remoteWidgetsList, ...localWidgetsList])]

    const definitions = fullWidgetsList.map(widgetName => {
        return ({
              name: widgetName,
              baseUrl: localWidgetsConfig.find(widget => widget.uniqueIdentifier === widgetName) ? `/widgets/${widgetName}` : widgetsRemoteConfigJson.definitions.find(widget => widget.name === widgetName).baseUrl,
              modifiedDate: localWidgetsConfig.find(widget => widget.uniqueIdentifier === widgetName) ? new Date().toISOString() : widgetsRemoteConfigJson.definitions.find(widget => widget.name === widgetName).modifiedDate,
          })
      }
    )

    const instances = fullWidgetsList.map(widgetName => {
        if (localWidgetsLocationConfig.hasOwnProperty(widgetName)) {
            return {
                id: localWidgetsIds.get(widgetName),
                name: widgetName,
                location: localWidgetsLocationConfig[widgetName],
            }
        } else if (widgetsRemoteConfigJson.instances.find(widget => widget.name === widgetName)) {
            const widgetRemoteConfig = widgetsRemoteConfigJson.instances.find(widget => widget.name === widgetName)
            return {
                id: widgetRemoteConfig.id,
                name: widgetName,
                location: widgetRemoteConfig.location,
            }
        } else {
            console.log(clc.red(`Widget ${widgetName} wasn't found in the widgets config`))
            process.exit(1)
            return null
        }
    })

    return {
        configurationUrl: widgetsRemoteConfigJson.configurationUrl,
        definitions,
        instances,
    }
}

module.exports = {
    getLocalWidgetsConfig,
    getWidgetsConfiguration,
    getLocalDevWidgetIds,
    getWidgetsConfig
}
